DataFrame
- ein Werkzeug für das Arbeiten mit Tabellen¶Am besten vergleichbar ist ein DataFrame mit der Tabellenstruktur, die ihr aus Programmen wie z.B. Excel oder OpenOffice Calc kennt. Dataframes sind zweidimensionale Tabellen, deren Spalten Überschriften haben (können) und immer gleich lang sind (also dieselbe Anzahl an Dateneinträgen haben). Dabei darf eine Spalte immer nur den gleichen Datentyp (z.B. numerische oder logische Werte) beinhalten; ein Dataframe kann aber spaltenweise unterschiedliche Datentypen darstellen (was ein Datentyp genau ist, wirst Du im Kurs noch erfahren).
In dieser Lektion wirst Du lernen (a) wie man Dataframes in erstellt oder einliest, (b) wie Du Elemente/Werte in Dataframes ansprichst, (c) wie Du diese Elemente oder ganze Dataframes modifizierst und (d) wie Du Dataframes als .txt-Dateien exportieren bzw. speichern kannst.
pandas
- ein Pythonpaket für DataFrames¶Diejenigen unter Euch, die sich bereits mit R
beschäftigt haben, kennen den data.frame
als typischen, in R standardmäßig eingebautes Element. In Python wird der Dataframe über das Paket pandas
bereitgestellt.
import pandas as pd
Schau Dir mal die Hilfe für den DataFrame an. Weißt Du noch, wie das geht? Schreibe in die folgende Zeile pd.DataFrame
, dann, je nach Geschmack, 1-3 mal Shift + Tab
drücken.
Anhand des folgenden Skriptbeispiels lernen wir kurz wie Objektzuweisungen funktionieren, treffen Listen wieder (list
), und erfahren nochmal, dass eine list
auch unterschiedliche Datentypen beinhalten kann.
# Liste, die Zeichenketten ('strings') enthält
Dichter = ["Goethe", "Schiller", "Brecht"]
# Liste, die numerische Werte enthält
Sterbealter = [83, 46, 57]
# Liste, die logische Werte (wahr oder falsch) beinhaltet
Brillentraeger = [False, False, True]
# In den vorigen Beispiele enthielt eine Liste immer nur einen Datentyp.
# Dies ist generell empehlenswert, da das Mischen von Datentypen
# zu Problemen führen kann, wenn wir daraus DataFrames erzeugen wollen.
NotrufNr = [110, 112] # gut!
NotrufNr = [110, 112, "Mama"] # nicht gut!
Aus den drei Listen Dichter
, Sterbealter
und Brillentraeger
erstellen wir nun mit der Function pd.DataFrame
unseren ersten DataFrame
.
Beachtet im folgenden Feld die geschwungenen Klammern ({...}
). Sie erzeugen in Python einen dictionary
. Diesen habt Ihr in der letzten Vertiefungsaufgabe kennengelernt.
df = pd.DataFrame({"Dichter": Dichter, "Sterbealter": Sterbealter, "Brillentraeger": Brillentraeger})
df
Verschaffen wir uns zunächst einen Überblick über den DataFrame. Das ist bei unserem Objekt df
oben nicht so schwer, aber bei größeren Dataframes mit vielen Zeilen und Spalten sinnvoll.
# So erhalten wir die Zahl der Zeilen und Spalten
df.shape
# So erhalten wir einen raschen Überblick über Zeilen, Spalten und die enthaltenen Datentypen.
df.info()
# Für numerische Spalten erhalten wir so einen schnellen Überblick deskriptiver Statistiken
df.describe()
DataFrame
auswählen¶Es gibt wirklich viele Möglichkeiten, auf Elemente eines DataFrames zuzugreifen. Was meinen wir mit "Element"? Das können Zeilen, Spalten, einzelne Felder oder nach bestimmten Kriterien ausgewählte Teilmengen sein. Wir gehen mal ganz stumpf ein paar Optionen durch...
# Spalte mit Namen auswählen
df["Dichter"]
# Genau das gleiche, nur schicker...
df.Dichter
# Oder gleich mehrere Spalten mit einer Liste auswählen
df[["Dichter", "Sterbealter"]]
# Zeilen mit "Slices" auswählen (Achtung: Python-Indizierung beginnt bei 0)
df[0:2]
Bei dem Versuch, auf diese Weise eine einzelne Zeile auszuwählen, laufen wir aber erstmal vor die Wand...
df[1]
Hier versucht pandas
nämlich, eine Spalte mit Namen ("label") 1
zu finden und scheitert wortreich daran. Wir müssen uns also mit der sog. label-basierten Auswahl (label-based selection) auseinandersetzen. Das ist zunächst vielleicht etwas verwirrend, aber es wird schon gutgehen...Versuch und Irrtum!
Schauen wir uns nochmal unseren DataFrame an:
df
Links sehen wir eine Spalte, die eigentlich gar nicht zur Tabelle gehört - Zahlen von 0 bis 2.
Wir können sie uns vorstellen wie die Zeilennummern in Excel. Diese Spalte heißt index
. Über diesen Index können wir Zeilen auswählen. Das mag hier unnötig kompliziert wirken, wird aber ein richtig cooles Feature, wenn wir statt Zahlen von 0
bis n
z.B. einen Index haben, der aus Datumangaben besteht. Dann können wir nämlich ruck zuck Zeilen mit einem bestimmten Datum auswählen. Anstatt der Spaltenbezeichner in Excel (von A
, B
usw.) nutzen wir in pandas
übrigens die Spaltennamen - haben wir ja schon gemacht.
Um nun also die index
-Label für die Auswahl von Zeilen zu nutzen, müssen wir das .loc
Feature von pandas
nutzen.
# Erste Zeile
df.loc[0]
# Zweite Zeile, Spalten Dichter und Sterbealter
df.loc[1, ["Dichter", "Sterbealter"]]
# Zweite und dritte Zeile, Spalten Dichter und Sterbealter
df.loc[[1,2], ["Dichter", "Sterbealter"]]
# Bedingungen für eine Auswahl nutzen: Nur Brillenträger
df.loc[df.Brillentraeger]
# Bedingungen für eine Auswahl nutzen: Nur Dichter, die "jung" gestorben sind
df.loc[df.Sterbealter < 60]
Wenn man wirklich strikt nach Position auswählen möchte, nutzt man das .iloc
Feature. Man wählt auf diese Weise streng nach Position aus, sowohl für die Zeile als auch für die Spalten - also genauso wie bei einer Matrix. Aber Achtung: Die erste Position ist in Python immer 0
!
# 2. Zeile, 1. Spalte
df.iloc[1,0]
Wir wollen nun einen bereits erzeugten DataFrage modifizieren.
Eine kurze Recherche hat ergeben, dass Brecht nicht 57 sondern 58 Jahre alt wurde. Das wollen wir korrigieren. Dafür müssen wir zuerst den Wert, den wir ändern wollen, auswählen und ihm dann einen neuen Wert zuweisen. Wir wissen, dass Brecht an dritter Stelle in der Tabelle steht, also könnten wir den Eintrag mit df.loc[2, "Sterbealter]
ansprechen. Aber bei sehr großen Datensätzen möchte man nicht erst die Position raussuchen. Wir lassen also Python für uns suchen - wir haben das oben schonmal gemacht.
# Vorher
df
# Spalte "Sterbealter" dort ändern wo der Dichter "Brecht" heißt
df.loc[df.Dichter=="Brecht", "Sterbealter"] = 58
# Kontrolle
df
Yay.
Das Land der digitalen Dichter:innen und Denker:innen hat ja wohl noch mehr vorzuweisen als nur Goethe, Schiller und Brecht. Wir wollen unseren Dataframe also mit weiteren Einträgen (Zeilen) ergänzen. Außerdem wollen wir für alle Dichter:innen noch weitere Informationen (Spalten) hinzufügen. z.B. das Geschlecht.
Wir können eine neue Zeile an einer bestimmten Stelle einfügen (z.B. am Ende). Das "Ende" ergibt sich aus der Länge des DataFrames, welches wir über len(df)
ermitteln.
df.loc[len(df)] = ["von Droste-Hülshoff", 51, False]
# Kontrolle
df
Einfacher ist es aber, einen neuen Dataframe über concat
anzuhängen.
df2 = pd.DataFrame({"Dichter": ["Bachmann", "Seghers"], "Sterbealter": [47, 82], "Brillentraeger": [True, False]})
df2
# Mit dem ignore_index Argument sorgen wir dafür,
# dass der index für die neuen Einträge auch neu erzeugt wird.
df = pd.concat([df, df2], ignore_index=True)
# Kontrolle
df
Eine neue Spalte anzuhängen ist etwas einfacher. Um es nochmal für alle auszubuchstabieren, spezifieren wir das Geschlecht.
df["Geschlecht"] = ["m", "m", "m", "w", "w", "w"]
# Kontrolle
df
Es wird Zeit, endlich den Namen der ersten Spalte anzupassen.
df = df.rename(columns={"Dichter": "Dichter*in"})
df
Für Dataframes mit vielen Einträgen kann es hilfreich sein, Dateneinträge nach Größe zu sortieren, z.B. signifikante Werte (kleine p-values) nach vorne. Wie das grundsätzlich funktioniert folgt hier am Beispiel unserer Dichter und ihres Effizenzindexes.
df.sort_values("Sterbealter")
Die Spalte "Brillentraeger" ist einfach albern und unnötig. Gern löschen wir sie raus. Dafür benutzen wir die Funktion drop
und teilen ihr über das Argument labels
den Namen der zu löschenden Spalte mit und über das Argument axis
die Dimension (0 für Zeile, 1 für Spalte).
df = df.drop(labels=["Brillentraeger"], axis=1)
# Kontrolle
df
Mit filtern meinen wir im Zusammenhang mit Tabellen oft die Auswahl von Daten auf Grundlage bestimmter Kriterien. Typischerweise machen wir das bei DataFrame durch Erzeugung von Indexarrays, die genauso lang sind wie unser Datensatz und für jede Zeile ein True
(auswählen) oder ein False
enthalten - am Besten am Beispiel:
df.Sterbealter < 60
(df.Sterbealter < 60) & (df.Geschlecht == "w")
So könnnen wir direkt eine Auswahl treffen:
df.loc[(df.Sterbealter < 60) & (df.Geschlecht == "w")]
Wir haben nun den DataFrame
ein wenig kennengelernt. In der Praxis haben wir es mit weitaus umfangreichen Datensätzen zu tun, die wir nicht manuell in einen DataFrame schreiben. Stattdessen können wir den Inhalt aus Tabellendateien (z.B. .csv
oder .xlsx
-Dateien) mit pandas
einlesen und dann als Dataframe behandeln. Damit wird es im nächsten Teil weitergehen...