Behandling av store datamengder i Python - Matematikk 1P-Y - NA - NDLA

Hopp til innhald
Verktøy og mal

Behandling av store datamengder i Python

Med modulen Pandas kan vi bruke programmeringsspråket Python til å handtere store datasett, og modulen gjer at vi kan lese innhaldet i store datafiler inn i eit Python-program.

Nedlasting av datafiler frå Statistisk sentralbyrå

Når vi skal jobbe med store sett med data, er programmering eit nyttig verktøy. Mykje kan òg gjerast i rekneark, men her skal vi sjå på korleis vi kan bruke Python til å behandle store datasett.

Når vi skal behandle data i Python, er det første vi må gjere, å laste ned ei fil med dataa og lagre ho i eit formålstenleg format. Gode format å jobbe med er .txt og .csv. Når vi lastar ned filer med stort talmateriale frå ulike statistikkar, er det ofte lurt å bruke .csv.

Vi skal sjå på nokre data om mediebruk frå Statistisk sentralbyrå (SSB). Du finn datasettet som ei nedlastbar fil nedst på denne sida, men prøv helst å laste ned fila sjølv, på nettsida https://www.ssb.no/statbank/table/04495/.

Datasettet som er brukt i dømet, er henta frå Statistikkbanken til SSB. Datasettet inneheld opplysningar om kor mange minutt ein gjennomsnittsnordmann brukte på ulike medium per dag dei siste åra. Følg framgangsmåten nedanfor for å velje ut data frå nettsida:

  • Gå til nettsida (sjå over).
  • Sørg først for at "Minutt brukt til ulike medium ein gjennomsnittsdag" er vald i boksen "Statistikkvariabel".
  • Vel deretter alle medietypane i boksen "Medietype" ved å klikke på knappen med grøn hake (eller vel alle manuelt i menyen).
  • Vel åra 2010 til 2019 i boksen "År".
  • Trykk på knappen "Vis tabell".

Når du har gjort dette, vil nettsida vise ein tabell som du kan sjå utdrag frå nedanfor:

Utdrag av datatabell

Medium

2010

2011

2012

Papiravis

23

24

21

Fjernsyn

152

157

131

Radio

81

86

88

Spørsmål

Kva betyr talet 131 i ruta for fjernsyn i året 2012?

Svar

Tabellen viser minutt brukt på ulike medium ein gjennomsnittsdag. Talet 131 for fjernsyn i året 2012 fortel oss at ein nordmann i gjennomsnitt brukte 131 minutt per dag til å sjå på fjernsyn i 2012.

For å laste ned ei fil med desse dataa gjer du følgande:

  • Vel "Lagre data som..." til venstre for tabellen.
  • Vel "Semikolonserparert med overskrift(csv)".
  • Trykk "Lagre".
  • Kopier fila over til same mappe på pc-en som Python-programma dine ligg i. Det gjer det lettare å referere til fila i programmet som skal bruke ho.
  • Endre filnamnet til "ssbmedium.csv".

Innlesing av datafila

Python-modulen Pandas bruker vi både til å lese datafila inn i Python og til å behandle dataa etterpå. Pandas organiserer dataa i ein såkalla dataframe (ei dataramme), som er ein tabell med kolonne- og radoverskrifter, ikkje ulikt eit rekneark.

Før vi les datafila inn i Python, kan vi kort sjå på ho med eit reknearkprogram. Bruk datafila du har lasta ned (ssbmedium.csv), eller last ned datafila nedst på denne sida. Opne fila i eit rekneark. Datafila ser slik ut (ikkje alle kolonnane er tekne med):

Det er tre problem med denne datafila:

  1. Dei to første radene må fjernast.
  2. Det manglar tal fleire stader. På slike stader står det anten eitt eller to punktum, avhengig av kvifor det manglar tal (sjå forklaring på nettsida med tabellen).
  3. Kolonneoverskriftene er veldig lange. På biletet over har vi utvida kolonne B slik at vi får med heile overskrifta. Også dei andre talkolonnane har den same lange overskrifta. Vi, derimot, vil berre ha årstala.

Dei to første problema ordnar vi under sjølve innlesinga. Det siste fiksar vi seinare.

Kode for innlesinga

Kopier koden nedanfor og lim han inn i programmeringseditoren du vanlegvis bruker. Pass på at fila har same namn i filstrukturen på pc-en som i programkoden. Køyr programmet. Får du utskrift av dataa? Du får ganske sikkert ei lite lesbar utskrift, men dette kan du ordne seinare.

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

Forklaring av koden

Først må vi importere modulen Pandas. Ved å importere han som "pd" slepp vi å skrive heile modulnamnet når vi skal referere til han.

Kommandoen vi bruker for å lese inn fila, er "read_csv()". Variabelen data blir då ein dataframe. Vi må setje inn mange såkalla attributt i kommandoen for at innlesinga skal gå smertefritt:

  • ssbmedium.csv: Her skriv vi filnamnet (og eventuell adresse) på datafila som skal lesast.
  • index_col = 0: ((Attributtet "index_col" får verdien 0.) Her fortel vi Python at første kolonne skal vere overskrifter.
  • skiprows = (0, 1): Dette betyr at dei to første radene (rad nummer 0 og 1) i fila skal hoppast over. (Hugs at Python byrjar nummerering på null.)

  • Vi deler opp den lange kodelinja med teiknet \. Hugs at neste linje må rykkast inn.
  • sep = ";": Dersom vi ser på datafila med ein enkel editor, som for eksempel Notisblokk i Windows, vil vi finne at alle dataa er åtskilde frå kvarandre med semikolon. Dette attributtet fortel programmet at semikolon betyr "nytt tal".
  • na_values = [".", ".."]: Her listar vi opp det som skal vurderast som manglande data eller "ikkje-data". Akkurat i denne fila er manglande data symboliserte ved anten eitt eller to punktum, men kva for teikn som blir brukte, kan variere frå fil til fil. Attributtet na_values sørger for at teiknet blir omsett til "NaN", eller "Not_a_Number" i den interne datatabellen. Då skaper det ikkje meir krøll under den vidare behandlinga.

  • encoding = "latin-1": Dersom vi legg til dette attributtet, tek programmet høgde for at datafila inneheld skandinaviske bokstavar som æ, ø eller å. Dersom dette ikkje fungerer, prøv verdien "utf-8".

Til slutt skriv vi ut innhaldet av variabelen data på vanleg måte med kommandoen print(data).

Nye kolonneoverskrifter

Dessverre blir utskrifta dårleg lesbar på grunn av dei lange kolonneoverskriftene ("Minutt brukt til ..."). Vi skal erstatte overskriftene med berre årstala. Det gjer vi ved å lage ei liste med årstala og rett og slett skrive inn dei nye kolonneoverskriftene i variabelen data. Sidan vi har statistiske data for kvart år, kan vi bruke ei for-lykkje til å generere lista, som vi her har kalla K for kolonneoverskrift.

python
1K = []   # lagar ei tom liste K 
2startVerdi = 2010   # lagar variabel for det første årstalet
3for i in range(0, 10):
4    K.append(startVerdi + i)
5data.columns = K  # set radoverskriftene i variabelen data lik innhaldet av lista K 

Kopier inn koden over rett før print()-kommandoen. Det kan hende at det blir med litt "rusk" under kopieringa; dette må i så fall fjernast i programmeringseditoren. I for-lykkja blir det for kvar runde lagt til eit tal i lista K som er 1 større enn det førre. I programkoden har vi lagt til kommentarar ved hjelp av teiknet #.

Får du ein meir lesbar tabell no, om du legg til koden over før du skriv ut innhaldet av variabelen data? Det kan hende at du berre får utskrift av tala for dei 3–4 første åra og for dei 3–4 siste. Det er heilt normalt. No er dataa klar for meir behandling!

Statistiske data med kommandoen describe()

Modulen Pandas har ein eigen kommando for å hente ut ulike statistiske mål i ein dataframe. Vi skriv følgande:

python
1print(data.describe())

Resultatet skal likne på tabellen nedanfor, der vi berre har skrive inn tala for året 2010.

Statistiske data med describe()

2010

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å dataa

count
talet på observasjonar vi har i kolonnen
mean
gjennomsnittet av verdiane i kolonnen
std
standardavviket i kolonnen. Standardavviket fortel oss noko om kor stor spreiing det er i datamaterialet. Viss standardavviket er stort, betyr det at vi har mange observasjonar som ligg langt unna gjennomsnittet. Viss vi bevegar oss eitt heilt standardavvik opp og ned frå gjennomsnittsverdien, skal vi ha ca 2/3 av alle observasjonane i dette intervallet.
min
minimumsverdien i kolonnen
25%
den nedste kvartilen. Dette talet fortel oss at 25 prosent av observasjonane i kolonnen er lågare enn denne verdien.
50%
medianen. Dette talet fortel oss at 50 prosent av observasjonane i kolonnen er lågare enn denne verdien.
75%
den øvste kvartilen. Dette talet fortel oss at 75 prosent av observasjonane i kolonnen er lågare enn denne verdien (og at 25 prosent av observasjonane er høgare enn denne verdien).
max
maksimumsverdien i kolonnen

Grafisk framstilling av dataa

Modulen Pandas har sin eigen plot()-kommando, som i sin tur bruker modulen Pyplot sin plot()-kommando (sjå teorisida "Teikne grafar med pyplot") til å lage framstillinga.

Vi ønsker å lage ei framstilling der vi ser korleis utviklinga har gått for dei ulike medietypane. Det betyr at vi ønsker å ha årstala på x-aksen.

Vi skriv følgande for å lage eit linjediagram av tala i variabelen data:

python
1data.plot()

Då får vi denne grafiske framstillinga:

Tips om du ikkje får fram den grafiske framstillinga

Dersom du bruker Jupyter Notebook:

  • Skriv %matplotlib inline øvst i koden.

Dersom du bruker Spyder:

  • Grafiske framstillingar dukkar opp i vindauget "Object", som ofte ligg over konsollvindauget til høgre ved standard oppsett i Spyder. Objektvindauget viser som standard hjelpeinformasjon, du må derfor velje "Plots" nedst i dette vindauget.

Generelt tips:

  • Skriv import matplotlib.pyplot as plt øvst i koden.

  • Skriv plt.show() nedst i koden.

Spørsmål

Kva viser denne grafiske framstillinga?

Forklaring

Vi har fått ei grafisk framstilling som viser korleis brukstala for dei ulike media varierer innanfor det enkelte året. Til dømes startar året 2019 med talet 9 for papiravis, held fram med talet 78 for fjernsyn og så vidare. (Vi kunne iallfall ha lese denne informasjonen ut av framstillinga om dei enkelte medietypane hadde stått oppførte langs x-aksen.)

Vi ønsker uansett det motsette, nemleg å sjå til dømes at tala for papiravis startar på 23 i 2010 og aukar til 24 i 2011. Problemet er at årstal ikkje vart oppfatta som den kategorien som skal vere på x-aksen.

Framstillinga blir feil. Vi kan fikse dette ved å byte om på rader og kolonnar i variabelen data før vi lagar plottet. Dette gjer vi med kommandoen transpose, sjå linje 1 i koden nedanfor. I tillegg ønsker vi å unngå at forklaringa kjem oppå grafikkfeltet. Det fiksar vi ved å legge til metoden "legend" til plot()-kommandoen og la attributtet "bbox_to_anchor" få verdien "(1, 1)", som er koordinatane til øvre høgre hjørne av plottet. Sjå linje 2.

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

Då får vi denne figuren:

No vart framstillinga riktig fordi vi køyrde kommandoen "transpose()" som transponerer tabellen ved å la radene bli kolonnar. Forklaringa la seg dessutan fint på sida av grafikkfeltet.

Spørsmål

Kvifor sluttar grafen for heime-pc i året 2014, mens grafen for digitale spel startar i 2016?

Forklaring

Grafane er avkorta når det ikkje er tal for åra før eller etter i tabellen. På den originale nettsida til SSB er det brukt eitt eller to punktum for å markere år utan tal.

Plotting av enkeltkolonnar

Dersom vi ønsker å samanlikne bruken av fjernsyn med bruken av internett, kan vi lage ein ny dataframe som berre inneheld dei kolonnane vi er interesserte i. Først vel vi ut radene med fjernsyn og internett frå dataframe-variabelen data, så legg vi dei i ein ny dataframe, og til slutt transponerer vi denne. Vi skriv følgande:

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

Her lagar vi ein ny dataframe-variabel utdrag som berre inneheld rad nummer 1 og 10 frå variabelen data, ved hjelp av metoden iloc.

NB: Hugs å fjerne tidlegare kommandolinjer med "transpose()" frå programmet ditt når du set inn linjene over.

Spørsmål

Kvifor brukte vi tala 1 og 10 i argumentet til metoden iloc?

Svar

Tala for fjernsyn står i andre rad, og tala for internett står i ellevte rad. Sidan radnummereringa byrjar på 0, må vi bruke 1 og 10 i kommandoen for å få vist desse radene.

Spørsmål

Er det tilfeldig at tala 1 og 10 er argument både i range-funksjonen i for-lykkja og i kommandoen med iloc?

Svar

Ja. Viss vi vel andre medietypar enn fjernsyn og internett, påverkar ikkje dette for-lykkja, men i iloc-kommandoen må vi setje inn nye tal.

Forbetring av den grafiske framstillinga

Vi kan forbetre den grafiske framstillinga ved hjelp av modulen Pyplot.

Spørsmål

Kva kan vi gjere dersom vi vil forbetre den grafiske framstillinga av tala for fjernsyn og internett? Kva manglar i figuren?

Forslag
  • Det manglar aksetitlar.
  • Det kunne vore ein tittel over diagrammet.
  • Statistisk sentralbyrå har gitt dataa sine til allmenta, men på det vilkåret at dei blir oppgitt som kjelde. Det bør altså stå "Kjelde: Statistisk sentralbyrå" ein eller annan stad i framstillinga.
  • Det kunne vore rutenett, for då blir det lettare å lese verdiar ut av diagrammet.

Oppgåve

Kommandoane nedanfor endrar den grafiske framstillinga i samsvar med forslaget vårt. Skriv dei inn og observer kva som skjer. Prøv å forklare kva kvar av dei fire kommandoane gjer.

Skriv øvst i programkoden (om du ikkje alt har gjort det):

python
1import matplotlib.pyplot as plt

Dette må du gjere for å kunne bruke funksjonane i Pyplot i programmet. Skriv så nedst i programkoden:

python
1plt.xlabel("Årstal")
2plt.ylabel("Minutt per dag i gjennomsnitt")
3plt.title("Tid brukt på fjernsyn og internett 2010–2019")
4plt.suptitle("Kjelde: Statistisk sentralbyrå", fontsize = 8)
5plt.grid(True)
Løysingsforslag
  • plt.xlabel lagar tittel på x-aksen.

  • plt.ylabel lagar tittel på y-aksen.

  • plt.title lagar tittelen over diagrammet.

  • plt.suptitle lagar kjeldetilvisninga til Statistisk sentralbyrå og plasserer ho over hovudtittelen. (Det er mogleg du må justere fontstorleiken til noko anna enn 8.)

  • plt.grid slår på rutenett.

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

Sjå òg teorisida "Teikne grafar med Pyplot" om du vil lese meir om forbetra framstilling av grafar.

Oppgåve

Lag ei tilsvarande grafisk framstilling der du samanliknar to eller tre ulike medietypar som du kan tenke deg å studere nærare.

Skrive av Tove Annette Holter og Bjarne Skurdal.
Sist fagleg oppdatert 01.06.2022