In een vorige tutorial heb je kennisgemaakt met pandas, een veelgebruikte tool voor het werken met gegegevens in Python.
In pandas werk je voornamelijk met gegevens in een DataFrame (of een Series), maar je gegevens komen vaak ergens anders vandaan. In deze tutorial leer je hoe je gegevens inleest vanuit CSV, Excel en JSON. Ook leer je hoe je een DataFrame weer opslaat in één van deze formaten.
Voordat je begint
Maak een nieuw project aan, met een nieuwe virtual environment. Installeer daarin ook pandas.
shell
cdprojects
mkdirpandas_gegevens&&cdpandas_gegevens
python-mvenv.venv
source.venv/bin/activate# .venv\Scripts\activate.bat voor Windows
python-mpipinstallpandas
python-mpipfreeze>requirements.txt
Alle code voorbeelden en voorbeeldbestanden van dit project zijn ook op Github te bekijken.
Series en DataFrames
Veelal zul je in pandas met Series en DataFrames werken. Maar wat is een DataFrame precies? Je kunt een DataFrame het best vergelijken met een tabel zoals je die ziet als je een spreadsheet opent (bijvoorbeeld in Excel). Je hebt dus rijen en kolommen.
De donkergrijze rij bevat de kolomnamen en de donkergrijze eerste kolom bevat de index (rijnummers of namen).
Series
Omdat een kolom van het type Series is, is het handig om hiermee te beginnen. Een Series is een 1-dimensionale lijst die elk type data kan bevatten, bijvoorbeeld int, str of date. Voor beginners is het soms verwarrend, maar een Series heeft ook een index, ofwel labels.
De donkergrijze blokken zijn samen de index, terwijl de lichtgrijze blokken de gegevens bevatten. Dus een Series is 1-dimensionaal (het is één lijst met gegevens), maar elk gegeven heeft wel een index. Maak je een Series aan zonder de index te specificeren, dan loopt de index simpelweg van 0 tot n.
Om een Series te maken, plaats je in main.py bovenin de import import pandas as pd. Deze manier van pandas importeren is een gewoonte die is ontstaan en die je overal zult zien. Het is dus handig jezelf dit ook aan te leren.
Vervolgens kun je een eenvoudige Series maken zonder index op te geven. Plaats hiervoor een lijst met gegevens in pd.Series().
main.py
importpandasaspd# Maak een Series aan zonder indexs=pd.Series(["aap","noot","mies"])print(s)
0 aap
1 noot
2 mies
dtype: object
Je ziet dat de index nu loopt van 0 t/m 2. Verder zie je dtype: object. Dit is kort voor datatype. In dit geval is het type "object", wat elk Python-object kan omvatten, inclusief str. Standaard slaat pandas tekst op als "object". Dit kan voor fouten zorgen, want een object kan ook iets anders zijn, en je kunt dus per ongeluk verschillende objecten in je Series plaatsen.
Om dit te voorkomen kun je opgeven dat je string of pd.StringDtype() als dtype wilt:
main.py
# Maak een Series aan zonder index, met type `str`s=pd.Series(["aap","noot","mies"],dtype="string")# s = pd.Series(["aap", "noot", "mies"], dtype=pd.StringDtype())print(s)
0 aap
1 noot
2 mies
dtype: string
Je ziet dat dtype nu wel "string" is.
Je kunt ook een eigen index meegeven:
main.py
# Maak een Series aan met indexs=pd.Series(["aap","noot","mies"],index=["a","b","c"],dtype="string")print(s)
a aap
b noot
c mies
dtype: string
En nu kun je de waarde op index "a" ophalen:
main.py
# Haal waarde op index 'a' opaap=s["a"]print(aap)# aap
Tot slot kun je ook een Series aanmaken op basis van een dict, waarbij de keys de index zullen vormen. Vergeet dan niet de dtype achteraf nog in te stellen op "string".
main.py
# Maak een Serie op basis van een `dict`d={"a":"aap","b":"noot","c":"mies"}s=pd.Series(d).astype("string")# Stel de dtype in op "string"print(s)
a aap
b noot
c mies
dtype: string
DataFrame
Een DataFrame is feitelijk een combinatie van meerdere Series, waarbij de index van de Series vervalt en de DataFrame als geheel een index krijgt.
main.py
# Maak een DataFrame op basis van een `dict` van `Series`.data={"kolom1":s,# s is de eerder aangemaakte Serie"kolom2":s,# s is de eerder aangemaakte Serie}df=pd.DataFrame(data)print(df.head())
kolom1 kolom2
a aap aap
b noot noot
c mies mies
Met df.head() toon je de eerste 5 rijen van een DataFrame. Je ziet dat de keys van de dict de kolomnamen zijn geworden. De index is ingesteld op "a", "b" en "c", omdat beide Series dit ook hadden. Kan pandas geen goede index bepalen, dan zal het simpelweg 0, 1, 2 worden.
Je kunt een DataFrame ook maken op basis van een dict met lijsten. Stel ook de index in.
main.py
# Maak een DataFrame op basis van een `dict` van lijstendata={"kolom1":[1,2,3],"kolom2":[4,5,6]}df=pd.DataFrame(data,index=["rij1","rij2","rij3"])print(df.head())
kolom1 kolom2
rij1 1 4
rij2 2 5
rij3 3 6
Je kunt nu een enkele kolom ophalen op basis van de kolomnaam:
main.py
# Haal een kolom op op basis van labelkolom1=df["kolom1"]print(kolom1)
rij1 1
rij2 2
rij3 3
Name: kolom1, dtype: int64
Met .loc[] haal je een rij op, op basis van de index.
main.py
# Haal een rij op op basis van indexrij_2=df.loc["rij2"]print(rij_2)print(type(rij_2))
Omdat de documentatie van pandas soms overweldigend kan zijn, zullen we in de toekomst ook aparte tutorials wijden aan het werken met Series en DataFrames, en dan met name het selecteren van gegevens.
CSV
Een CSV-bestand (Comma Separated Values) is een veelgebruikt bestandsformaat voor het uitwisselen van gegevens tussen verschillende applicaties. Het is een eenvoudig tekstbestand waarin elke regel een gegevensrecord voorstelt en de waarden in elk record door komma's (of puntkomma's) van elkaar gescheiden zijn. CSV-bestanden zijn populair omdat ze eenvoudig te openen en bewerken zijn in een teksteditor en omdat je er eenvoudig mee kunt werken in allerlei programma's en programmeertalen.
Opslaan als CSV
Maak nogmaals een eenvoudige Dataframe aan:
main.py
# Maak een DataFrame op basis van een `dict` van lijstendata={"kolom1":[1,2,3],"kolom2":[4,5,6]}df=pd.DataFrame(data,index=["rij1","rij2","rij3"])print(df.head())
Deze Dataframe sla je nu eenvoudig op naar een CSV-bestand. Je gebruikt hiervoor de methode to_csv. Dit is een instance-methode, dus je roept het aan vanaf je net aangemaakte Dataframe: df.to_csv().
Er zijn veel opties beschikbaar voor to_csv. In de meeste gevallen heb je er maar enkele nodig. De belangrijkste is natuurlijk het eerste argument: het pad naar een CSV-bestand. Verder zijn sep en index nog interessant. Met sep geef je aan wat het scheidingsteken moet zijn. Standaard is dit een komma (,), maar zelf geef ik altijd de voorkeur aan ;. Ook kies ik er meestal voor de index niet weg te schrijven in het CSV-bestand, zodat je een schoon bestand overhoudt met enkel de kolomnamen en de gegevens. Het geheel ziet er dan zo uit:
main.py
# Schrijf de DataFrame naar een CSV-bestanddf.to_csv("df1.csv",sep=";",index=False)
En zo eenvoudig is het: je hebt een CSV-bestand genaamd df1.csv opgeslagen! Voor alle opties van to_csv lees je de documentatie. Overigens kun je to_csv ook op een Series aanroepen.
CSV inlezen
Andersom - dus het inlezen van een CSV-bestand naar een DataFrame - werkt net zo eenvoudig. Je gebruikt hiervoor read_csv. Deze roep je aan vanaf pd (pandas). Ook hier geef je weer een bestandsnaam op en eventueel het scheidingsteken (als dat geen komma is).
main.py
# Lees een CSV-bestand in naar een DataFramedf1=pd.read_csv("df1.csv",sep=";")print(df1.head())
Ook hier zijn weer veel extra opties mogelijk die helpen bij het goed inlezen van de data. Een paar verdienen extra aandacht.
Datum
Met parse_dates en date_format kun je aangeven welke kolommen een datum bevatten, en in welk formaat. Stel dat je een CSV-bestand genaamd datums.csv hebt met de volgende inhoud:
Met parse_dates en date_format kun je nu aangeven hoe pandas de kolom Datum moet inlezen.
main.py
# Lees een CSV-bestand in met een datum kolomdf_datums=pd.read_csv("datums.csv",sep=";",parse_dates=["Datum"],date_format="%Y-%m-%d")print(df_datums.dtypes)
Datum datetime64[ns]
Aantal int64
dtype: object
Je ziet dat Datum nu een dtype van datetime65[ns] heeft, wat wil zeggen dat het niet meer een tekst is, maar echt een datum-formaat. Dit maakt het mogelijk om er allerlei datumafhankelijke bewerkingen mee te doen, zoals het groeperen op maand, of eenvoudig selecteren van alle vrijdagen om maar iets te noemen.
Zie de documentatie van strftime om te leren hoe de datumnotatie werkt.
Missende waarden
Een ander handigheidje is dat je kunt bepalen hoe er met missende waarden omgegaan moet worden. Standaard worden al heel wat teksten herkend als missende waarden, namelijk:
Maar heb je zelf ook waarden die als missend herkend moeten woorden, bijvoorbeeld ?, dan kan dat met na_values. Neem bijvoorbeeld het CSV-bestand missend.csv met de volgende inhoud:
missend.csv
kolom1;kolom2
1;4
2;?
3;6
Regel 2, kolom 2 bevat een vraagteken wat pandas moet herkennen als missende waarde.
main.py
# Lees een CSV-bestand met missende waarden indf_missend=pd.read_csv("missend.csv",sep=";",na_values="?")print(df_missend.head())
kolom1 kolom2
0 1 4.0
1 2 NaN
2 3 6.0
Je ziet dat op regel 2, kolom 2 nu geen vraagteken meer bevat, maar NaN, waarmee pandas aangeeft dat het een missende waarde is (Not a Number).
Er zijn nog veel meer mogelijkheden met read_csv, veel heb je alleen in uitzonderlijke gevallen nodig. Bekijk de volledige documentatie om meer te leren.
Excel
Je hebt leren werken met CSV-bestanden, een formaat dat je veel tegenkomt om gegevens uit te wisselen. Een ander veel voorkomend formaat is Excel. Ook hier kan pandas goed mee omgaan, en eigenlijk werkt het vrijwel hetzelfde als werken met CSV. In plaats van to_csv heb je to_excel en in plaats van read_csv heb je read_excel. De opties zijn grotendeels hetzelfde.
Er is echter één belangrijk verschil: voor het werken met Excel heb je nog een andere package nodig die het daadwerkelijk lezen/schrijven doet. Er zijn enkele pakketen beschikbaar:
Installeer één van deze pakketten in je venv, zodat pandas ermee kan werken. Je hoeft verder niets te importeren, dat handelt pandas voor je af.
Een belangrijk verschil tussen CSV en Excel is dat je in een Excel-bestand meerdere werkbladen (sheets) kunt hebben. Met de parameter sheet_name kun je aangeven welke sheet(s) je wilt inlezen. Standaard staat dit op 0, het eerste werkblad. Je kunt de index gebruiken, of de naam van een werkblad. Je kunt ook een lijst met meerdere werkbladen opgeven. Het resultaat is dan een dict met de namen als sleutel en de DataFrames als waarde.
Een kort voorbeeld. Installeer eerst openpyxl:
shell
python-mpipinstallopenpyxl
Vervolgens kun je het tweede werkblad van een Excel-bestand genaamd excel.xlxs inlezen.
main.py
# Lees het tweede werkblad van een Excel-bestand indf_excel=pd.read_excel("excel.xlsx",sheet_name=1)print(df_excel.head())
7 10
0 8 11
1 9 12
Om een DataFrame naar Excel te schrijven, gebruik je to_excel, wat vrijwel hetzelfde werkt als to_csv. Ook hiervoor heb je een extra package nodig. Je kunt hiervoor xlsxwriter of openpyxl gebruiken.
Lees de documentatie om meer te leren over het werken met Excel.
JSON
Ook het werken met JSON is redelijk vergelijkbaar als met CSV-bestanden en Excel-bestanden. Maar daar waar CSV en Excel erg lijken op een DataFrame (rijen en kolommen), is dit bij JSON niet het geval.
Een extra optie bij to_json en read_json is dan ook orient, waarmee je bepaalt hoe de vertaalslag van rijen/kolommen naar of van een meer dict-achtige structuur gemaakt moet worden. De standaard bij DataFrames is columns.
Stel je hebt het volgende JSON-object, opgeslagen in json-bestand.json:
De volgende code leest het bestand in en zet het om naar een DataFrame:
main.py
# Lees een JSON bestand indf_json=pd.read_json("json-bestand.json")print(df_json.head())
Het resultaat is dan dat de eerste sleutels ("kolom1", "kolom2") de kolom-koppen worden. De tweede-niveau sleutels ("rij1", "rij2", "rij3") vormen de index.
kolom1 kolom2
rij1 1 4
rij2 2 5
rij3 3 6
Zie de documentatie om meer te leren over de verschillende oriëntatiemogelijkheden.
Andere bestanden
Naast het werken met CSV, Excel en JSON zijn er nog tal van andere mogelijkheden om gegevens naar op te slaan of vanuit te openen. Een aantal voorbeelden zijn HTML, XML, Parquet en SQL. Zie de documentatie voor een volledige lijst en alle mogelijkheden.
Conclusie
Gegevens kunnen overal vandaan komen en veel verschillende formaten hebben. In pandas zul je echter meestal met een DataFrame of een Series werken. Gelukkig heeft pandas vele methoden om eenvoudig gegevens in te lezen of juist weg te schrijven naar bijvoorbeeld CSV, Excel en JSON.
Alle methodes werken ongeveer hetzelfde. Gebruik to_* om naar een bepaald formaat te schrijven en gebruik read_* om vanuit een bepaald formaat in te lezen. Voor de details kun je altijd de documentatie erbij pakken!
Alle code voorbeelden en voorbeeldbestanden van dit project zijn ook op Github te bekijken.
Over de auteur
Erwin Matijsen
Erwin is de oprichter van python-cursus.nl. In allerlei rollen heeft hij Python ingezet, van het eenvoudiger maken van zijn werk tot het opleveren van complete (web)applicaties. Met vrouw en kinderen woont hij in Havelte (Drenthe), midden in de prachtige natuur. Daar wandelt hij graag, zeker ook omdat de beste ingevingen tijdens een wandeling - weg van de computer - lijken te komen.
Training volgen?
Heb je behoefte aan een in-person training voor jezelf of je team?
Dat kan! Laat je gegevens achter en dan nemen we zo snel mogelijk contact met je op de mogelijkheden te bespreken.
Vragen, opmerkingen?
Heb je vragen, opmerkingen, suggesties of tips naar aanleiding van deze blog?
Neem dan contact met ons op, of laat het weten via
Mastodon of
LinkedIN.