Hopp til innhold
SubjectMaterialFagstoff

Verktøy og mal

Behandling av store datamengder i Python

Med modulen Pandas kan vi bruke programmeringsspråket Python til å håndtere store datasett, og modulen gjør at vi kan lese innholdet i store datafiler inn i et Python-program.

FooterHeaderIconFooter iconLK20

Når vi skal jobbe med store sett med data, er programmering et nyttig verktøy. Mye kan også gjøres i regneark – men her skal vi se på hvordan vi kan bruke Python til å behandle store datasett.

Nedlasting av datafiler fra Statistisk Sentralbyrå

Når vi skal behandle data i Python, er det første vi må gjøre å laste ned en fil med dataene og lagre den i et hensiktsmessig format. Gode format å jobbe med er .txt og .csv. Når vi laster ned filer med stort tallmateriale fra ulike statistikker, er det ofte lurt å bruke .csv.

Vi skal se på noen data om mediebruk fra Statistisk sentralbyrå (SSB). Du finner datasettet som en nedlastbar fil nederst på denne sida, men prøv helst å laste ned fila selv, på nettsida https://www.ssb.no/statbank/table/04495/.

Datasettet som er brukt i eksemplet, er henta fra Statistikkbanken til SSB. Datasettet inneholder opplysninger om hvor mange minutter en gjennomsnittsnordmann brukte på ulike medier per dag de siste årene. Følg framgangsmåten nedenfor for å velge ut data fra nettsida:

  • Gå til nettsida (se over).
  • Sørg først for at "Minutter brukt til ulike medier en gjennomsnittsdag" er valgt i boksen "Statistikkvariabel".
  • Velg deretter alle medietypene i boksen "Medietype" ved å klikke på knappen med grønn hake (eller velg alle manuelt i menyen).
  • Velg årene 2010 til 2019 i boksen "År".
  • Trykk på knappen "Vis tabell".

Når du har gjort dette, vil nettsida vise en tabell som du kan se utdrag fra nedenfor:

2010

2011

2012

...

Papiravis

23

24

21

Fjernsyn

152

157

131

Radio

81

86

88

...

Spørsmål

Hva betyr tallet 131 i ruten for fjernsyn i året 2012?

Svar

Tabellen viser minutter brukt på ulike medier en gjennomsnittsdag. Tallet 131 for fjernsyn i året 2012 viser at en nordmann i gjennomsnitt brukte 131 minutter per dag til å se på fjernsyn i 2012.

For å laste ned en fil med disse dataene gjør du følgende:

  • Velg "Lagre data som..." til venstre for tabellen.
  • Velg "Semikolonseparert med overskrift (csv)".
  • Trykk "Lagre".
  • Kopier fila over til samme mappe på pc-en som Python-programmene dine ligger i. Det gjør det lettere å referere til fila i programmet som skal bruke den.
  • Endre filnavnet til "ssbmedier.csv".

Innlesing av datafila

Python-modulen Pandas bruker vi både til å lese datafila inn i Python og til å behandle dataene etterpå. Pandas organiserer dataene i en såkalt dataframe (dataramme), som er en tabell med kolonne- og radoverskrifter, ikke ulikt et regneark.

Før vi leser datafila inn i Python, kan vi kort se på den med et regnearkprogram. Bruk datafila du har lasta ned (ssbmedier.csv), eller last ned datafila nederst på denne sida. Åpne fila i et regneark. Datafila ser slik ut (ikke alle kolonner er tatt med):

Regneark som viser antall minutter brukt på ulike medier, blant annet papiraviser, fjernsyn og internett, på en gjennomsnittsdag. Tallene dekker årene 2010 til og med 2019. Skjermutklipp.

Visning av datafil fra SSB i regneark.

Det er tre problemer med denne datafila:

  1. De to første radene må fjernes.
  2. Det mangler tall flere steder. På slike steder står det enten ett eller to punktum, avhengig av hvorfor det mangler tall (se forklaring på nettsida med tabellen).
  3. Kolonneoverskriftene er veldig lange. På bildet over har vi utvidet kolonne B slik at vi får med hele overskriften. Også de andre tallkolonnene har den samme lange overskriften. Vi derimot vil bare ha årstallene.

De to første problemene ordner vi under selve innlesingen. Det siste fikser vi etterpå.

Kode for innlesingen

Kopier koden nedenfor og lim den inn i programmeringseditoren du vanligvis bruker. Pass på at fila har samme navn i filstrukturen på pc-en som i programkoden. Kjør programmet. Får du utskrift av dataene? Du får ganske sikkert en dårlig lesbar utskrift, men dette kan du ordne senere.

Python

1
2
3
4
import pandas as pd
data = pd.read_csv("ssbmedier.csv", index_col = 0, skiprows = (0, 1), \
    sep =";", na_values=[".", ".."], encoding = "latin-1")
print(data)

Forklaring av koden

Først må vi importere modulen Pandas. Ved å importere den som "pd" slipper vi å skrive hele modulnavnet når vi skal referere til den.

Kommandoen vi bruker for å lese inn fila, er "read_csv()". Variabelen data blir da en dataframe. Vi må sette inn mange såkalte attributter i kommandoen for at innlesingen skal gå smertefritt.

  • ssbmedier.csv: Her skriver vi filnavnet (og eventuell adresse) på datafila som skal leses.
  • index_col = 0: Her forteller vi Python at første kolonne skal være overskrifter.
  • skiprows = (0, 1): Dette betyr at de to første radene (rad nr. 0 og 1) i fila skal hoppes over. (Husk at Python begynner nummerering på null.)
  • Vi deler opp den lange kodelinjen med tegnet \. Husk at neste linje må rykkes inn.
  • sep = ";": Dersom vi ser på datafila med en enkel tekstbehandler, vil vi finne at alle dataene er atskilt fra hverandre med semikolon. Dette attributtet forteller programmet at semikolon betyr "nytt tall".
  • na_values = [".", ".."]: Her lister vi opp det som skal betraktes som manglende data eller "ikke-data". Akkurat i denne fila er manglende data symbolisert ved enten ett eller to punktum, men hvilke(t) tegn som brukes, kan variere fra fil til fil. Attributtet na_values sørger for at tegnet blir oversatt til "NaN", eller "Not_a_Number" i den interne datatabellen. Da skaper det ikke mer krøll under den videre behandlingen.
  • encoding = "latin-1": Dersom vi legger til dette attributtet, tar programmet høyde for at datafila inneholder skandinaviske bokstaver som æ, ø eller å.

Til slutt skriver vi ut innholdet av variabelen data på vanlig måte med kommandoen print(data).

Nye kolonneoverskrifter

Dessverre blir utskriften dårlig lesbar på grunn av de lange kolonneoverskriftene ("Minutter brukt til ..."). Vi skal erstatte overskriftene med bare årstallene. Det gjør vi ved å lage en liste med årstallene og rett og slett skrive inn de nye kolonneoverskriftene i variabelen data. Siden vi har statistiske data for hvert år, kan vi bruke en for-løkke til å generere lista, som vi her har kalt K for kolonneoverskrift:

Python

1
2
3
4
5
K = []   # Lager en tom liste K 
K.append(2010)   # Legger inn det første årstallet
for i in range(1, 10):
    K.append(K[i-1]+1)
data.columns = K  # Setter radoverskriftene i variabelen data lik innholdet av lista K 

Kopier inn koden over rett før print()-kommandoen. Det kan hende at det blir med noe "rusk" under kopieringen; dette må i så fall fjernes i programmeringseditoren. I for-løkka blir det for hver runde lagt til et tall i lista K som er 1 større enn det forrige. I programkoden har vi lagt til kommentarer ved hjelp av tegnet #.

Får du en mer lesbar tabell, nå dersom du legger til koden over før du skriver ut innholdet av variabelen data? Det kan hende at du bare får utskrift av tallene for de 3–4 første årene og for de 3–4 siste. Det er helt normalt. Nå er dataene klar for mer behandling!

Statistiske data med kommandoen describe()

Modulen Pandas har en egen kommando for å hente ut ulike statistiske mål i en dataframe. Vi skriver følgende:

Python

1
print(data.describe())

Resultatet skal ligne på tabellen nedenfor, der vi bare har skrevet inn tallene for året 2010:

2010

2011

...

2018

2019

count

11.000000

mean

44.727273

std

48.203923

min

1.000000

25%

8.000000

50%

23.000000

75%

78.500000

max

152.000000

Forklaring på dataene

  • count: tallet på observasjoner vi har i kolonnen
  • mean: gjennomsnittet av verdiene i kolonnen
  • std: standardavviket i kolonnen. Standardavviket forteller oss noe om hvor stor spredning det er i datamaterialet. Hvis standardavviket er stort, betyr det at vi har mange observasjoner som ligger langt unna gjennomsnittet. Hvis vi beveger oss ett helt standardavvik opp og ned fra gjennomsnittsverdien, skal vi ha ca 2/3 av alle observasjonene i dette intervallet.
  • min: minimumsverdien i kolonnen
  • 25%: den nederste kvartilen. Dette tallet forteller oss at 25 prosent av observasjonene i kolonnen er lavere enn denne verdien.
  • 50%: medianen. Dette tallet forteller oss at 50 prosent av observasjonene i kolonnen er lavere enn denne verdien.
  • 75%: den øverste kvartilen. Dette tallet forteller oss at 75 prosent av observasjonene i kolonnen er lavere enn denne verdien (og at 25 prosent av observasjonene er høyere enn denne verdien).
  • max: maksimumsverdien i kolonnen

Grafisk framstilling av dataene

Modulen Pandas har sin egen plot()-kommando, som i sin tur bruker modulen Pyplot sin plot()-kommando (se sida Tegne grafer med Pyplot) til å lage framstillingen.

Vi ønsker å lage en framstilling der vi ser hvordan utviklingen har gått for de ulike medietypene. Det betyr at vi ønsker å ha årstallene på x-aksen.

Vi skriver følgende for å lage et linjediagram av tallene i variabelen data:

Python

1
data.plot()

Da får vi følgende grafiske framstilling:

Eksempel på feil ved grafisk framstilling. På x-aksen skulle det vært årstall, men i stedet er det medietypene som er plassert der. Hver dataserie skulle vært en medietype, ikke årstall som her. Skjermutklipp.
Tips om du ikke får fram den grafiske framstillingen

Dersom du bruker Jupyter Notebook:

  • Skriv %matplotlib inline øverst i koden.

Dersom du bruker Spyder:

  • Grafiske framstillinger dukker opp i vinduet "Object", som ofte ligger over konsollvinduet til høyre ved standard oppsett i Spyder. Objektvinduet viser som standard hjelpeinformasjon, du må derfor velge "Plots" nederst i dette vinduet.

Generelt tips:

  • Skriv import matplotlib.pyplot as plt øverst i koden.
  • Skriv plt.show() nederst i koden.

Spørsmål

Hva viser denne grafiske framstillingen?

Forklaring

Vi har fått en grafisk framstilling som viser hvordan brukstallene for de ulike mediene varierer innenfor det enkelte året. For eksempel starter året 2019 med tallet 9 for papiravis, fortsetter med tallet 78 for fjernsyn osv. (Vi kunne iallfall ha lest denne informasjonen ut av framstillingen om de enkelte medietypene hadde stått oppført langs x-aksen.)

Vi ønsker oss uansett det motsatte, nemlig å se for eksempel at tallene for papiravis starter på 23 i 2010 og øker til 24 i 2011. Problemet er at årstall ikke ble oppfatta som den kategorien som skal være på x-aksen.

Framstillingen blir feil. Vi kan fikse dette ved å bytte om på rader og kolonner i variabelen data før vi lager plottet. I tillegg ønsker vi å unngå at forklaringen kommer oppå grafikkfeltet. Derfor legger vi til attributtet "bbox_to_anchor" sammen med metoden "legend". Vi erstatter plot()-kommandoen med koden nedenfor:

Python

1
2
data = data.transpose()
data.plot().legend(bbox_to_anchor = (1, 1))

Da får vi følgende figur:

Linjediagram som viser bruken av ulike medier, for eksempel papiraviser, fjernsyn og internett, i årene 2010 til 2019. Skjermutklipp.

Bruk av ulike medietyper i årene 2010 til 2019.

Nå ble framstillingen riktig fordi vi kjørte kommandoen "transpose()" som transponerer tabellen ved å la radene bli kolonner. Forklaringen la seg dessuten pent på sida av grafikkfeltet.

Spørsmål

Hvorfor slutter grafen for hjemme-pc i året 2014, mens grafen for digitale spill starter i 2016?

Forklaring

Grafene er avkorta når det ikke er tall for årene før eller etter i tabellen. På den originale nettsida til SSB er det brukt ett eller to punktum for å markere år uten tall.

Plotting av enkeltkolonner

Dersom vi ønsker å sammenlikne bruken av fjernsyn med bruken av internett, kan vi lage en ny dataframe som bare inneholder de kolonnene vi er interessert i. Først velger vi ut radene med fjernsyn og internett fra dataframe-variabelen data, så legger vi dem i en ny dataframe, og til slutt transponerer vi denne. Vi skriver følgende:

Python

1
2
3
utdrag = data.iloc[[1, 10]]
utdrag = utdrag.transpose()
utdrag.plot().legend(bbox_to_anchor = (1, 1))

Her lager vi en ny dataframe-variabel utdrag som bare inneholder rad nr. 1 og 10 fra variabelen data, ved hjelp av metoden iloc.

Bruken av fjernsyn og internett i antall minutter per dag i årene 2010 til 2019, framstilt som linjediagram. Internettbruken øker kraftig, mens fjernsynsbruken synker tilsvarende. Skjermutklipp.

Bruk av fjernsyn og internett i årene 2010 til 2019.

Spørsmål

Hvorfor brukte vi tallene 1 og 10 i argumentet til metoden iloc?

Svar

Tallene for fjernsyn står i andre rad, og tallene for internett står i 11. rad. Siden radnummereringen begynner på 0, må vi bruke 1 og 10 i kommandoen for å få vist disse radene.

Spørsmål

Er det tilfeldig at tallene 1 og 10 er argumenter både i range-funksjonen i for-løkka og i kommandoen med iloc?

Svar

Ja. Hvis vi velger andre medietyper enn fjernsyn og internett, påvirker ikke dette for-løkka, men i iloc-kommandoen må vi sette inn nye tall.

Forbedring av den grafiske framstillingen

Vi kan forbedre den grafiske framstillingen ved hjelp av modulen Pyplot.

Spørsmål

Hva kan vi gjøre dersom vi vil forbedre den grafiske framstillingen av tallene for fjernsyn og internett? Hva mangler i figuren?

Forslag
  • Det mangler aksetitler.
  • Det kunne vært en tittel på diagrammet øverst.
  • Statistisk sentralbyrå har gitt dataene sine til allmennheten, men på det vilkåret at de blir oppgitt som kilde. Det bør altså stå "Kilde: Statistisk sentralbyrå" ett eller annet sted på framstillingen.
  • Det kunne vært rutenett, for da blir det lettere å lese verdier ut av diagrammet.

Oppgave

Kommandoene nedenfor endrer den grafiske framstillingen i samsvar med forslaget vårt. Skriv dem inn og observer hva som skjer. Prøv å forklare hva hvert av de fire kommandoene gjør.

Skriv øverst i programkoden (om du ikke alt har gjort det):

Python

1
import matplotlib.pyplot as plt 

Dette må du gjøre for å kunne bruke funksjonene i Pyplot i programmet. Skriv så nederst i programkoden:

Python

1
2
3
4
5
plt.xlabel("Årstall")
plt.ylabel("Minutter per dag i gjennomsnitt")
plt.title("Tid brukt på fjernsyn og internett 2010–2019")
plt.suptitle("Kilde: Statistisk sentralbyrå", fontsize = 8)
plt.grid(True)

Løsningsforslag

Bruken av fjernsyn og internett i årene 2010 til 2019, framstilt som linjediagram. Figuren har tittelen "Årstall" på x-aksen og tittelen "Minutter per dag i gjennomsnitt" på y-aksen. Hovedtittelen er "Tid brukt på fjernsyn og internett 2010–2019", og over tittelen står det at kilden er Statistisk sentralbyrå.  Skjermutklipp.

Bruk av fjernsyn og internett 2010–2019, forbedra figur.

  • plt.xlabel lager tittel på x-aksen.
  • plt.ylabel lager tittel på y-aksen.
  • plt.title lager tittelen over diagrammet.
  • plt.suptitle lager kildehenvisningen til Statistisk sentralbyrå og plasserer den over hovedtittelen. (Det er mulig du må justere fontstørrelsen til noe annet enn 8.)
  • plt.grid slår på rutenett.

Det kan hende du må skrive plt.show() for å få fram figuren.

Se også sida Tegne grafer med Pyplot om du vil lese mer om forbedra framstilling av grafer.

Filer

Oppgave

Lag en tilsvarende grafisk framstilling der du sammenlikner to eller tre ulike medietyper som du kan tenke deg å studere nærmere.

Sist oppdatert 04.05.2021
Skrevet av Bjarne Skurdal og Tove Annette Holter

Læringsressurser

Grafer og store datasett i Python