Pandas-Tutorial

So geht Datenanalyse mit Python

16.04.2024 von Serdar Yegulalp
Mit Pandas können Sie Daten(tabellen) direkt in Python laden, verändern, zusammenführen und sogar visualisieren. Unser Tutorial zeigt Ihnen, wie das funktioniert.
Mit Pandas (und Python) zeigen Sie Excel-Enthusiasten, was Sache ist.
Foto: Cik Bak - shutterstock.com

Geht es darum, mit Daten in Tabellenform zu arbeiten, greifen die meisten Menschen zur Tabellenkalkulation. Das ist per se keine schlechte Wahl: Microsoft Excel und ähnliche Programme sind vertraut und bieten zahlreiche Funktionen, um Daten in Tabellenform zu bearbeiten. Schwierig wird es dann, wenn Sie mehr Kontrolle, Präzision und Leistung brauchen, als Excel und Co. bieten.

In diesem Fall könnte die Open-Source-Bibliothek Pandas für Python genau das Richtige für Sie sein: Sie stattet die Programmiersprache mit neuen Datentypen aus, um Informationen möglichst schnell aus tabellarischen Quellen zu laden und diese (unter anderem) in großem Umfang zu verändern, auszurichten und zusammenzuführen. Die Kombination aus Python und Pandas bietet diverse Funktionen, die mit einer Tabellenkalkulation nicht zur Verfügung stehen.

Sie können damit Ihre Daten-Tasks automatisieren und die Ergebnisse reproduzierbar machen. Anstatt klobige und limitierte Makros zu erstellen, können Sie mit Pandas Daten analysieren, segmentieren und transformieren. Die ausdrucksstarke Natur von Python und das umfassende Ökosystem sorgen dabei dafür, dass Sie noch bessere Ergebnisse erzielen, als mit Pandas alleine.

Pandas-Datensatz erstellen

Pandas ist ein Drittanbieterprojekt und somit nicht Teil der Python-Standardbibliothek. Sie müssen es also in Ihrer Laufzeitumgebung mit dem Befehl pip install pandas installieren. Sobald das geschehen ist, folgt der Import in Python mit:

import pandas

Pandas führt zwei neue Datentypen ein:

Der DataFrame repräsentiert Ihr gesamtes Tabellenblatt beziehungsweise Ihre Daten, während Series eine einzelne Spalte des DataFrame repräsentiert. Sie können sich den Pandas DataFrame auch als ein Wörterbuch oder eine Sammlung von Series-Objekten vorstellen.

Normalerweise arbeiten Sie mit Pandas, indem Sie Daten in einem anderen Format importieren. Ein gängiges tabellarisches Datenformat ist .csv - eine Textdatei mit Werten, die durch Kommas getrennt sind. Für unser Tutorial verwenden wir einen Auszug aus dem Gapminder-Datenset, der von Jennifer Bryan an der University of British Columbia erstellt wurde.

Um mit Pandas loszulegen, gilt es zunächst, die Bibliothek zu importieren. Um Tipparbeit zu sparen, ist es dabei üblich, Pandas mit dem Alias pd zu versehen:

import pandas as pd

Um mit den Beispieldaten im .csv-Format arbeiten zu können, laden wir diese mit der Funktion pd.read_csv als DataFrame:

df = pd.read_csv("./gapminder/inst/extdata/gapminder.tsv", sep='\t')

Mit dem sep-Parameter können wir dabei angeben, dass diese spezielle Datei tabulator- und nicht kommagetrennt ist. Sobald die Daten geladen sind, können Sie deren Formatierung überprüfen, um sicherzustellen, dass sie korrekt eingeladen wurden. Das funktioniert, indem Sie die Methode .head() für den DataFrame verwenden:

print(df.head())

country continent year lifeExp pop gdpPercap

0 Afghanistan Asia 1952 28.801 8425333 779.445314

1 Afghanistan Asia 1957 30.332 9240934 820.853030

2 Afghanistan Asia 1962 31.997 10267083 853.100710

3 Afghanistan Asia 1967 34.020 11537966 836.197138

4 Afghanistan Asia 1972 36.088 13079460 739.981106

DataFrame-Objekte weisen das Attribut shape auf. Das gibt Auskunft über die Anzahl der Zeilen (Rows) und Spalten (Columns) im DataFrame:

print(df.shape)

(1704, 6) # rows, cols

Um die Namen der Spalten selbst aufzulisten, verwenden Sie .columns:

print(df.columns)

Index(['country', 'continent', 'year', 'lifeExp',

'pop', 'gdpPercap'], dtype='object')

DataFrames in Pandas funktionieren ähnlich wie die in anderen Sprachen, beispielsweise Julia und R. Jede Spalte - oder Series - muss vom gleichen Typ sein, während Zeilen gemischte Typen enthalten können. In unserem Beispiel ist die country-Spalte immer ein String und die year-Spalte immer eine ganze Zahl. Das können wir überprüfen, indem wir .dtypes verwenden, um den Datentyp jeder Spalte aufzulisten:

print(df.dtypes)

country object

continent object

year int64

lifeExp float64

pop int64

gdpPercap float64

dtype: object

Für eine noch genauere Aufschlüsselung der Typen innerhalb Ihres DataFrame können Sie .info() nutzen:

df.info() # information is written to console, so no print required

<class 'pandas.core.frame.DataFrame'>

RangeIndex: 1704 entries, 0 to 1703

Data columns (total 6 columns):

# Column Non-Null Count Dtype

--- ------ -------------- -----

0 country 1704 non-null object

1 continent 1704 non-null object

2 year 1704 non-null int64

3 lifeExp 1704 non-null float64

4 pop 1704 non-null int64

5 gdpPercap 1704 non-null float64

dtypes: float64(2), int64(2), object(2)

memory usage: 80.0+ KB

Jeder Pandas-Datentyp wird auf einem nativen Python-Pendant abgebildet:

Spalten und Zeilen in Pandas

Nachdem Sie nun einen einfachen Datensatz laden können, möchten Sie auch dessen Inhalte inspizieren. Sie könnten dazu auf den print-Befehl setzen - allerdings sind die meisten DataFrames dafür zu groß. Ein besserer Ansatz besteht darin, nur eine Teilmenge der Daten zu betrachten - ähnlich wie wir es bereits mit df.head() gemacht haben, aber mit mehr Kontrollmöglichkeiten. Indem Sie Pythons bestehende Syntax nutzen, um Slices zu erstellen und zu indizieren, können Sie mit Pandas auch DataFrame-Auszüge erstellen.

Spalten extrahieren

Um einzelne Spalten in einem Pandas-DataFrame zu untersuchen, können Sie diese anhand ihrer Namen, Positionen oder Bereiche extrahieren. Wenn Sie beispielweise eine spezifische Spalte aus Ihrem Datensatz benötigen, können Sie sie mit Hilfe eckiger Klammern nach ihrem Namen abfragen:

# extract the column "country" into its own dataframe

country_df = df["country"]

# show the first five rows

print(country_df.head())

| 0 Afghanistan

| 1 Afghanistan

| 2 Afghanistan

| 3 Afghanistan

| 4 Afghanistan

Name: country, dtype: object

# show the last five rows

print(country_df.tail())

| 1699 Zimbabwe

| 1700 Zimbabwe

| 1701 Zimbabwe

| 1702 Zimbabwe

| 1703 Zimbabwe

| Name: country, dtype: object

Falls Sie mehrere Spalten extrahieren wollen, übergeben Sie eine Liste der betreffenden Spaltennamen:

# Looking at country, continent, and year

subset = df[['country', 'continent', 'year']]

print(subset.head())

country continent year

| 0 Afghanistan Asia 1952

| 1 Afghanistan Asia 1957

| 2 Afghanistan Asia 1962

| 3 Afghanistan Asia 1967

| 4 Afghanistan Asia 1972

print(subset.tail())

country continent year

| 1699 Zimbabwe Africa 1987

| 1700 Zimbabwe Africa 1992

| 1701 Zimbabwe Africa 1997

| 1702 Zimbabwe Africa 2002

| 1703 Zimbabwe Africa 2007

Zeilen extrahieren

Wenn Sie Zeilen (Rows) aus einem DataFrame extrahieren möchten, stehen Ihnen dazu bei Pandas zwei Methoden zur Verfügung:

  1. .iloc[] ist die einfachste Methode. Sie extrahiert Zeilen basierend auf ihrer Position, beginnend bei 0. Um die erste Zeile im obigen Beispiel eines DataFrames einzuladen, würden Sie folglich df.iloc[0] verwenden. Wenn Sie einen Bereich einer Zeile abrufen möchten, können Sie .iloc[] in Kombination mit der Slicing-Syntax von Python verwenden. Für die ersten zehn Zeilen würden Sie beispielsweise df.iloc[0:10] verwenden. Wenn Sie spezifische Zeilen extrahieren möchten, können Sie auch eine Liste der Zeilen-IDs verwenden, etwa df.iloc[[0,1,2,5,7,10,12]]. Beachten Sie dabei die doppelten Klammern - sie bedeuten, dass Sie eine Liste als erstes Argument angeben.

  2. Die andere Möglichkeit, Zeilen zu extrahieren, ist .loc[]. Dies extrahiert eine Teilmenge auf der Grundlage der Beschriftungen der Zeilen. Standardmäßig werden die Zeilen mit einem aufsteigenden ganzzahligen Wert (beginnend mit 0) gelabelt. Die Daten können aber auch manuell beschriftet werden, indem Sie die .index-Property des DataFrame festlegen. Wenn wir zum Beispiel den obigen DataFrame neu indizieren wollten, so dass jede Zeile einen Index mit Vielfachen von 100 aufweist, könnten wir dazu df.index = range(0, len(df)*100, 100) verwenden. Wenn wir anschließend df.loc[100] verwenden, würden wir die zweite Zeile erhalten.

Spalten extrahieren

Für den Fall dass Sie nur eine bestimmte Untergruppe von Spalten zusammen mit Ihren Zeilen-Slices abrufen möchten, übergeben Sie eine entsprechende Liste von Spalten als zweites Argument:

df.loc[[rows], [columns]]

Wenn wir etwa aus dem obigen Beispiel-Datensatz ausschließlich die Spalten "Country" und "Year" für alle Zeilen abrufen wollen, gehen wir wie folgt vor:

df.loc[:, ["country","year"]]

Der : bedeutet "alle Zeilen" (das ist Pythons Slicing-Syntax). Die Liste der Spalten folgt nach dem Komma. Sie können auch Spalten nach Position angeben, indem Sie .iloc verwenden:

df.iloc[:, [0,2]]

Das funktioniert auch, wenn Sie nur die ersten drei Spalten brauchen:

df.iloc[:, 0:3]

All diese Ansätze lassen sich miteinander kombinieren, insofern Sie loc für Labels und Spaltennamen und iloc für numerische Indizes verwenden. Im Folgenden weisen wir Pandas an, die ersten 100 Zeilen anhand ihrer numerischen Bezeichnungen zu extrahieren und das anschließend für die ersten drei Spalten (anhand ihrer Indizes) zu wiederholen:

df.loc[0:100].iloc[:, 0:3]

Um Verwirrung zu vermeiden, empfiehlt es sich, bei der Unterteilung von Daten die tatsächlichen Spaltennamen zu verwenden. Dadurch ist der Code leichter zu lesen - und Sie müssen nicht auf den Datensatz zurückgreifen, um herauszufinden, welche Spalte welchem Index entspricht. Außerdem bewahrt Sie das vor Fehlern, wenn die Spalten neu geordnet werden.

Berechnungen mit Pandas

Tabellenkalkulationen und Bibliotheken, die mit Zahlen arbeiten, verfügen über Methoden, um Statistiken über Daten zu erstellen. Betrachten wir an dieser Stelle noch einmal die Gapminder-Daten:

print(df.head(n=10))

| country continent year lifeExp pop gdpPercap

| 0 Afghanistan Asia 1952 28.801 8425333 779.445314

| 1 Afghanistan Asia 1957 30.332 9240934 820.853030

| 2 Afghanistan Asia 1962 31.997 10267083 853.100710

| 3 Afghanistan Asia 1967 34.020 11537966 836.197138

| 4 Afghanistan Asia 1972 36.088 13079460 739.981106

| 5 Afghanistan Asia 1977 38.438 14880372 786.113360

| 6 Afghanistan Asia 1982 39.854 12881816 978.011439

| 7 Afghanistan Asia 1987 40.822 13867957 852.395945

| 8 Afghanistan Asia 1992 41.674 16317921 649.341395

| 9 Afghanistan Asia 1997 41.763 22227415 635.341351

Zu diesem Datensatz könnten wir beispielsweise folgende Fragen stellen:

Um diese mit Pandas beantworten zu können, braucht es eine "grouped" oder "aggregated" Berechnung. Dabei können wir die Daten entlang bestimmter Linien aufteilen, eine Berechnung auf jedes aufgeteilte Segment anwenden und dann die Ergebnisse in einem neuen DataFrame zusammenführen.

Gruppierte Mittelwerte zählen

Die erste Methode, die wir dafür verwenden, ist Pandas' df.groupby()-Operation. Dazu geben wir eine Spalte an, nach der wir die Daten aufteilen wollen:

df.groupby("year")

Auf diese Weise können wir alle Zeilen mit demselben Jahres-Wert als ein vom DataFrame getrenntes Objekt behandeln. Unter diesen Voraussetzungen können wir die Spalte "Lebenserwartung" (lifeExp) verwenden und ihren Mittelwert für jedes enthaltene Jahr berechnen:

print(df.groupby('year')['lifeExp'].mean())

year

1952 49.057620

1957 51.507401

1962 53.609249

1967 55.678290

1972 57.647386

1977 59.570157

1982 61.533197

1987 63.212613

1992 64.160338

1997 65.014676

2002 65.694923

2007 67.007423

Daraus ergibt sich die durchschnittliche Lebenserwartung für alle Bevölkerungsgruppen, aufgeschlüsselt nach Jahren. Eine ähnliche Berechnung könnten wir für die Bevölkerung (pop) und das BIP pro Jahr (gdpPercap) nutzen:

print(df.groupby('year')['pop'].mean())

print(df.groupby('year')['gdpPercap'].mean())

Wenn wir unsere Daten allerdings nach mehr als einer Spalte gruppieren wollen, übergeben wir Spalten in Listen:

print(df.groupby(['year', 'continent'])

[['lifeExp', 'gdpPercap']].mean())

lifeExp gdpPercap

year continent

1952 Africa 39.135500 1252.572466

Americas 53.279840 4079.062552

Asia 46.314394 5195.484004

Europe 64.408500 5661.057435

Oceania 69.255000 10298.085650

1957 Africa 41.266346 1385.236062

Americas 55.960280 4616.043733

Asia 49.318544 5787.732940

Europe 66.703067 6963.012816

Oceania 70.295000 11598.522455

1962 Africa 43.319442 1598.078825

Americas 58.398760 4901.541870

Asia 51.563223 5729.369625

Europe 68.539233 8365.486814

Oceania 71.085000 12696.452430

Diese .groupby()-Operation gruppiert unsere Daten zunächst nach Jahr und anschließend nach Kontinent. Dann werden Mittelwerte aus den Spalten Lebenserwartung und BIP gebildet. Auf diese Weise können Sie Ihre Daten gruppieren und festlegen, wie sie dargestellt und in welcher Reihenfolge sie berechnet werden sollen.

Wenn Sie die Ergebnisse in einem einzigen, inkrementell indizierten Rahmen "glätten" möchten, können Sie die .reset_index()-Methode auf die Ergebnisse anwenden:

gb = df.groupby(['year', 'continent'])

[['lifeExp', 'gdpPercap']].mean()

flat = gb.reset_index()

print(flat.head())

| year continent lifeExp gdpPercap

| 0 1952 Africa 39.135500 1252.572466

| 1 1952 Americas 53.279840 4079.062552

| 2 1952 Asia 46.314394 5195.484004

| 3 1952 Europe 64.408500 5661.057435

| 4 1952 Oceana 69.255000 10298.085650

Gruppierte Häufigkeiten zählen

Ein weiterer häufiger Use Case für Daten sind Häufigkeitsberechnungen. Um eindeutige Werte in einer Reihe - und ihre Häufigkeit zu ermitteln - lassen sich die Methoden nunique und value_counts verwenden. So lässt sich zum Beispiel herausfinden, wie viele Länder zu den jeweiligen Kontinenten (siehe Eingangsfragen) gehören:

print(df.groupby('continent')['country'].nunique())

continent

Africa 52

Americas 25

Asia 33

Europe 30

Oceana 2

Visualisierungsgrundlagen mit Pandas und Matplotlib

Geht es darum, Daten zu visualisieren, kommt in den meisten Fällen eine weitere Bibliothek zum Einsatz - beispielsweise Matplotlib. Diese Library können Sie auch verwenden, um Datenvisualisierungen direkt aus Pandas heraus zu erstellen. Um die einfache Matplotlib-Erweiterung für Pandas zu verwenden, stellen Sie zunächst sicher, dass Sie Matplotlib installiert haben:

pip install matplotlib

Werfen wir nun noch einmal einen Blick auf die Beispieldaten - und hier auf die durchschnittliche, jährliche Lebenserwartung der Weltbevölkerung:

global_yearly_life_expectancy = df.groupby('year')['lifeExp'].mean()

print(global_yearly_life_expectancy)

| year

| 1952 49.057620

| 1957 51.507401

| 1962 53.609249

| 1967 55.678290

| 1972 57.647386

| 1977 59.570157

| 1982 61.533197

| 1987 63.212613

| 1992 64.160338

| 1997 65.014676

| 2002 65.694923

| 2007 67.007423

| Name: lifeExp, dtype: float64

So erstellen Sie aus diesem Datensatz eine einfache Visualisierung:

import matplotlib.pyplot as plt

global_yearly_life_expectancy = df.groupby('year')['lifeExp'].mean()

c = global_yearly_life_expectancy.plot().get_figure()

plt.savefig("output.png")

Das zugehörige Diagramm wird in einer Datei im aktuellen Arbeitsverzeichnis als output.png gespeichert. Die Achsen und andere Labels im Diagramm lassen sich manuell setzen. Diese Methode eignet sich auch gut für schnelle Exporte. (fm)

Dieser Beitrag basiert auf einem Artikel unserer US-Schwesterpublikation Infoworld.