Uke 14 -- Pandas examples
=========================
.. note::
pandas er et eksternt bibliotek som vi må installere først i terminalen::
python -m pip install --user pandas
Hvis dette ikke fungerer så kan du prøve å kjøre denne koden:
:download:`install.py`, som prøver å finne den riktige versjonen til Python med::
import sys
print(sys.executable)
Denne gangen skal vi se på `Pandas `_-biblioteken,
med det samme datasettet vi har brukt før.
Pandas er en veldig nyttig bibliotek til dataanalyse, som gjør det enkelt å få til
mange av de vanlige ting man vil gjøre. Mer detalj finnes i introduksjonen her::
* https://pandas.pydata.org/docs/getting_started/overview.html
* https://pandas.pydata.org/docs/getting_started/intro_tutorials/index.html
.. * https://pandas.pydata.org/docs/getting_started/10min.html
Akvakultur
----------
Last inn datasettet
...................
FIlen er det samme som før: :download:`Akvakulturregisteret.csv`.
Fra `instructions on opening files `_
ser vi at vi bør bruke :code:`read_csv`. Første forsøket er ::
import pandas as pd
akva = pd.read_csv('Akvakulturregisteret.csv')
print(akva.columns)
Flere ting går feil her: vi må fortelle pandas om at filen bruker :code:`;` som separator, og at
filen er kodert som :code:`iso-8859-1`. Også er det litt uvanlig at informasjon
om kolonnenavn finnes i rad 1, ikke 0. La oss legge til alt dette::
import pandas as pd
import matplotlib.pyplot as plt
akva = pd.read_csv(
'Akvakulturregisteret.csv',
delimiter=';',
encoding='iso-8859-1',
header=1
)
print(akva.columns)
print(akva)
Det ser ut som at det fungerer allerede. Sammenlignet med CSV-modulen har vi mye mer informasjon inni
pandas-dataframet :code:`akva`. Kolonnenavn ble satt automatisk, og vi kan skrive ut
ulik informasjon med f.eks::
print(akva['ART'])
print(akva['POSTSTED'].min(), akva['POSTSTED'].max())
Slicing og filtrering fungerer slik som vi så med numpy::
filter = (akva['ART'] == 'Laks')
print(akva[filter])
Plotting
........
La oss se på visualisering.
`Tutorial on plotting `_
er veldig nyttig. Det ser ut at vi kun trenger en linje til, for å få en scatterplot
til alle posisjoner:
.. literalinclude:: akva_pd_1.py
.. image:: akva_pd_1.png
Oppgavene fra CSV-kapittel
..........................
De ulike dataanalyse-oppgavene vi så tidligere kan enkelt gjøres med pandas:
* Telle opp ulike arter (*ART*, column 12). Googling *count categories in pandas*
foreslår :code:`value_counts()`::
print(akva['ART'].value_counts())
* Plotte kun de som oppdrar *Laks*. Her kan vi bruke filtere::
laks = akva[ akva['ART'] == 'Laks' ]
laks.plot.scatter(x='Ø_GEOWGS84', y='N_GEOWGS84', alpha=0.2))
* Plot *FERSKVANN* i en farge og *SALTVANN* in en annen (*VANNMILJØ*, column 20). Igjen bruker vi filtere.
Scatter plots vi bruker her er vanlige matplotlib plots, ikke de som kommer direkte fra pandas.
Vi ser hvor enkelt det er å kombinere disse ulike bibliotekene:
.. literalinclude:: akva_pd_2.py
.. image:: akva_pd_2.png
Flere eksempler
---------------
Below are a few examples (in English) of using pandas, matplotlib, and numpy to
deal with large datasets:
.. toctree::
:maxdepth: 1
bergensveret/index
geophys3/index
tides-and-sea-level/index
hydrostatic-balance/index
Summary
-------
Pandas er ett av de flestbrukte dataanalyseverktøy i realfag, og tilbyr mye mer enn
det vi kan vise i en innføringsforelesning til Python. Om du synes det er nyttig for deg, start på
pandas-nettsiden og følg med i de ulike tutorials, med tanke på dine egne datasett.
Oppgaver
--------
Denne ukas oppgaver er **valgfrie**, for de som vil prøve, og **kommer ikke å bli
testet eller satt karakter på**.
Oppgave 1 - Pandas
....................
I denne oppgaven skal vi jobbe med datasettet :download:`VIK_sealevel_2000.txt` som inneholder målinger
av havnivå for hver time av året 2000.
- **a)** skriv en funksjon :code:`read_data` som tar inn et filnavn og returnerer en pandas dataframe
der den første kolonnen (index) skal ha navnet ``date`` og innholder :code:`datetime`.
De andre kolonnene skal ha navn ``year month day hour sealevel``.
Du kan anta at filen har samme format som :code:`VIK_sealevel_2000.txt`.
Tips: her er det lurt å se på `read_csv `_
og `to_datetime `_
Eksempelkjøring for pandas dataframe. Obs! hour må være 0-23, ikke 24! ::
>>> print(data.head())
year month day hour sealevel
date
2000-01-01 00:00:00 2000 1 1 0 335
2000-01-01 01:00:00 2000 1 1 1 336
2000-01-01 02:00:00 2000 1 1 2 338
2000-01-01 03:00:00 2000 1 1 3 341
2000-01-01 04:00:00 2000 1 1 4 347
- **b)** skriv en funksjon :code:`plot_months` som tar inn en dataframe formatert som i **a)** og plotter
en graf som viser gjennomsnittlig havninvå for hver måned. Gi grafen og aksene passende navn, og velg noen
fine farger.
- **c)** skriv en funksjon :code:`plot_rolling_average` som tar inn en dataframe formatert som i **a)**.
Funksjonen skal plotte havninvået for juni måned både direkte og som et glidende gjennomsnitt (rolling average).
Velg periode for det glidende gjennomsnittet selv. Grafen kan f.eks se sånn her ut:
.. image:: rolling_avg_june.png
Tips: se på `rolling `_
Oppgave 2 - Generell problemløsning
.....................................
Du og naboen din har begge like store hager. Hagene deres representeres som
2D-lister, hvor ``garden[i][j]``, gir et element på posisjonen ``(i, j)``. Hvert
element i en hage er representert som en streng, og kan være en av de følgende:
``"grass", "moss", "strawberry", "rock", "raspberry"``. Du har i det siste sett
at det har blitt litt vel mye mose og stein i hagen din, og mistenker at det er
naboen din som har lagt det der. For å fikse opp i dette, skal du fullføre
funksjonen ``clean_garden(my_garden, neighbors_garden)``. Her skal du først lage
små funksjoner for å gjøre det enklere å løse den faktiske oppgaven.
Til slutt skal du bytte ut hvert stein og mose fra din hage, med den første
jordbær og bringebær fra naboen sin hage som finnes
(de to ting som skal byttes trenger *ikke* å være på samme posisjon).
Last ned :download:`uke14_oppgave_2.py` og fullfør funksjonene:
- ``find_item`` som tar inn to argumenter: ``(garden, item)``, som
returnerer en ``(i, j)`` posisjon som en tuppel, hvis ``item`` finnes i
``garden``. Hvis det ikke finnes, returnerer du ``None``
- ``swap_items`` som bytter ut to elementer mellom to hager, la den ta
inn disse argumentene: ``(garden1, garden2, pos1, pos2)``, hvor ``pos1`` og
``pos2`` er ``(i, j)`` tupler. Her skal du ikke returnere noe, men endre listene du får inn
som argumenter.
**Bruk funksjonene du har skrevet til å fullføre**
``clean_garden(my_garden, neighbors_garden)``:
Bytt ut all "rock" med "strawberry", og "moss" med "raspberry" fra naboen sin hage
så lenge det finnes muligheter for bytte.
Oppgave 3 - Project Euler
.........................
En vanlig sikkerhetsmetode for banker er å spørre brukeren for tre random nummer fra en passkode. Om passkoden er
531278 og de spør etter 2., 3. og 5. nummer vil det riktige svaret være 317.
Filen :download:`keylog.txt ` inneholder 50 korrekte innloggingsforsøk. Gitt at de tre numrene de spør etter alltid er i rekkefølge,
bruk filen :download:`keylog.txt ` til å finne den korteste mulige passkoden av ukjent lengde.
Tips: bruk dict og list i kombinasjon: for hvert tall 1-9, lag en liste med tall som kommer
tidligere i rekkefølgen. Tallet der denne listen er tom, må være det første. (Løsningen
til dette datasett er 73162890)
.. note:: For de som har lyst til å programmere mer i løpet av desember så finnes
det en adventskalender med programmeringsoppgaver: `Advent of Code
`_. Det er ulike vanskelighetsgrad på de
ulike oppgavene, men du kan prøve og se hvor mange du kan løse. Om du
blir med: lykke til!