NumPy gir oss arrays (ndarray) for effektiv numerisk beregning. I stedet for løkker regner vi vektorisert på hele arrays om gangen, og broadcasting lar arrays av ulik form regne sammen. Dette er fundamentet for vitenskapelig databehandling i Python.
Læringsmål
01Forklare hva et NumPy-array er og hvordan det skiller seg fra en vanlig Python-liste med hensyn til type og lagring
02Bruke vektorisering til å regne på alle elementene i et array samtidig uten en eksplisitt løkke
03Forklare hva broadcasting gjør, og gjenkjenne det enkleste tilfellet der et array kombineres med ett enkelt tall
04Kombinere NumPy-arrays med plotting ved å lage x-verdier og regne ut y-verdier vektorisert
Si at du har målt temperaturen hvert minutt i et helt døgn og vil gjøre alle målingene om fra celsius til fahrenheit. Med en vanlig liste må du skrive en løkke som går gjennom hvert element, regner om, og legger resultatet i en ny liste. Det funker, men det er tregt, og koden blir lang. For tusen tall er det ikke noe problem; for ti millioner tall merker du det.
NumPy løser dette. Det er et bibliotek for numerisk beregning, og det innfører en ny datatype: et array. Du importerer det nesten alltid slik:
numpy-array
Lag et NumPy-array og regn vektorisert
python
1importnumpyasnp23temp = np.array([12.0, 14.5, 13.2, 15.8, 16.1, 14.0])45print(temp[0]) # 12.0 (indeksering som en liste)6print(temp[1:4]) # [14.5 13.2 15.8] (slicing)78# Vektorisert: regn på alle elementene samtidig, uten løkke9fahrenheit = temp * 9 / 5 + 3210print(fahrenheit)11print(temp.mean()) # gjennomsnitt av alle målingene
Vises her for å forklare mønsteret; kjør den i laben der NumPy er installert. Legg merke til at omregningen skjer på hele arrayet uten en eneste løkke.
Et array ligner på en liste, men det er ikke det samme. Et NumPy-array — fagnavnet er ndarray, for «n-dimensjonalt array» — krever at alle elementene har samme type. Et array av tall er bare tall, lagret tett etter hverandre i minnet. En liste kan blande tall, strenger og hva som helst, og hvert element er et eget objekt spredt rundt i minnet. Den tette, ensartede lagringen er hele grunnen til at NumPy er raskt.
FIGEt NumPy-array med seks temperaturmålinger
Figuren viser et array med seks temperaturmålinger. Hvert element har en indeks akkurat som i en liste, og du henter dem ut på samme måte med klammer: temp[0] er den første. Du kan også slice et array, temp[1:4], helt som med lister. Forskjellen ligger ikke i hvordan du leser enkeltelementer, men i hva du kan gjøre med hele arrayet på én gang.
Regn på alt samtidig
Her kommer det som gjør NumPy verdt å lære: vektorisering. I stedet for å løkke deg gjennom elementene, skriver du operasjonen på hele arrayet, og NumPy utfører den på alle elementene samtidig — med kode som internt kjører i et raskt, kompilert språk under panseret.
Tilbake til temperatur-eksempelet. Med en liste trenger du en løkke. Med et array skriver du:
Legg merke til at det ikke er noen løkke. Uttrykket celsius * 9 / 5 + 32 regnes ut for hvert element av seg selv. Dette er ikke bare kortere å skrive — det er ofte titalls ganger raskere enn en Python-løkke, fordi NumPy slipper å gå innom Python-tolkens trege maskineri for hvert eneste tall.
Vektorisering gjelder alle de vanlige regneoperasjonene, og NumPy har dessuten innebygde funksjoner som regner på hele arrayet: celsius.mean() gir gjennomsnittet, celsius.max() gir det største, celsius.sum() summerer alt. Disse er også vektorisert, så de er raske selv på enorme datamengder.
Å lage arrays
Du kommer til å lage arrays på noen få faste måter. Den enkleste er np.array([...]), der du gir en vanlig Python-liste og får et array tilbake. For å lage et array fylt med nuller eller enere bruker du np.zeros(n) og np.ones(n) — nyttig når du skal sette av plass og fylle inn verdier etterpå. To funksjoner er spesielt vanlige når du skal lage tallrekker:
np.arange(start, stopp, steg) ligner range: den teller fra start mot stopp i hopp på steg. np.linspace(start, stopp, antall) er litt annerledes — du sier hvor mange jevnt fordelte tall du vil ha mellom start og stopp, og NumPy regner ut steget for deg. Den siste er ofte den du vil ha når du skal lage x-verdier til en graf, fordi du vet hvor mange punkter du ønsker, ikke nødvendigvis hvor stort steget skal være.
Arrays kan også ha mer enn én dimensjon. Et array av arrays blir en tabell — en rad per indre liste — og brukes til matriser, bilder og tabelldata. Du indekserer da med to tall, tabell[rad, kolonne]. For ITGK holder det å vite at muligheten finnes; det meste du møter er endimensjonale arrays, altså vanlige tallrekker.
Når formene ikke stemmer
I eksempelet over ganget vi et array med tallet 9 — ett enkelt tall, ikke et array. Hvordan vet NumPy at 9 skal brukes på hvert element? Svaret er en mekanisme som heter broadcasting: når formene på det du regner med ikke er like, strekker NumPy automatisk det minste ut så det passer det største, uten å faktisk kopiere data.
Den enkleste formen er nettopp et array ganger et tall: tallet «kringkastes» til alle elementene. Litt mer avansert: et array med en rad kan legges til et array med flere rader, og NumPy gjentar raden nedover. Broadcasting følger faste regler om hvilke former som passer sammen, og det er en vanlig kilde til forvirring i starten — får du en feilmelding om at former ikke kan «broadcastes», betyr det at NumPy ikke fant en lovlig måte å strekke dem på. For ITGK holder det å vite at et array pluss eller ganger et tall virker på alle elementene, og at det er broadcasting som gjør det mulig.
En liten advarsel om operasjoner mellom to arrays. Når du legger sammen to arrays med a + b, legges elementene sammen parvis: første pluss første, andre pluss andre, og så videre. Det forutsetter at de har samme lengde (eller former som kan broadcastes). Dette er ikke det samme som å skjøte to lister med + i vanlig Python, der [1, 2] + [3, 4] blir [1, 2, 3, 4]. NumPy-arrays regner; Python-lister skjøter. Å blande de to mentale modellene er en klassisk nybegynnerfelle — husk at så snart du har gjort om til array, betyr + elementvis addisjon.
Et lite, praktisk eksempel som binder det sammen: si at du har målt nedbør hver dag i en uke og vil vite hvor mange dager det regnet mer enn snittet. Med NumPy går det på et par linjer — regn snittet med .mean(), lag en sammenligning på hele arrayet (nedbor > snitt gir et array av sanne/usanne verdier), og tell hvor mange som er sanne med .sum(). Ingen løkke, ingen tellevariabel. Det er denne stilen — uttrykk på hele arrayet i stedet for skritt-for-skritt-løkker — som er kjernen i å bruke NumPy godt.
Arrays og grafer hører sammen
NumPy brukes nesten alltid sammen med plotting. Du lager gjerne et array av x-verdier, regner ut tilhørende y-verdier med en vektorisert formel, og tegner resultatet. Plottet under viser nettopp dette: et array med x-verdier kjørt gjennom y = x**2, der hver y er regnet ut vektorisert i ett jafs.
FIGy = x**2 regnet ut vektorisert over et array
Funksjonen np.linspace(start, stopp, antall) er arbeidshesten her — den lager et array med jevnt fordelte tall, perfekt som x-akse. Sammen med vektorisering får du fra noen få linjer kode en glatt kurve, uten en eneste løkke. I neste kapittel ser vi nærmere på selve plottingen med Matplotlib; her er poenget at NumPy leverer tallene den tegner.
Hvorfor kjøres koden i laben
Kode-eksemplene i dette kapittelet vises i teksten, men NumPy er et eksternt bibliotek som ikke alltid er tilgjengelig i en helt enkel kjøreflate. Derfor er det laben som er stedet å faktisk kjøre NumPy-koden — der er biblioteket på plass, og du kan eksperimentere med arrays, vektorisering og broadcasting selv. Les eksemplene her for å forstå mønstrene, og prøv dem ut i laben for å se dem virke.
Oppsummert. Et NumPy-array lagrer mange tall av samme type tett i minnet, og det er derfor raskt. Vektorisering lar deg regne på hele arrayet uten løkke, og er både kortere og mye raskere enn å løkke gjennom en liste. Broadcasting strekker mindre former ut så de passer større — enklest når du ganger et array med ett tall. Og NumPy og plotting går hånd i hånd: lag x-verdier, regn ut y-verdier vektorisert, tegn.
Mine notater
Skriv egne notater for dette kapittelet. De lagres automatisk og dukker opp i «Mine notater»-oversikten paa fag-siden.