Pandas-Pivot-Tabelle: Daten wie in Excel zusammenfassen und umformen (Guide)
Updated on
Jede Analystin und jeder Analyst, die/der mit Excel gearbeitet hat, kennt Pivot-Tabellen. Du ziehst ein Feld in den Zeilenbereich, ein anderes in den Spaltenbereich, wählst eine Zusammenfassungsfunktion – und aus einem dichten Spreadsheet voller Rohtransaktionen wird eine saubere Übersicht: Summen nach Kategorie, Durchschnittswerte nach Region oder Anzahlen pro Monat. Jetzt willst du das Gleiche in Python machen, aber verschachtelte groupby-Aufrufe mit unstack wirken umständlich und sind schwer zu lesen.
Die eigentliche Frustration kommt, wenn deine Daten mehrere Gruppierungsebenen haben, du Zwischensummen brauchst oder mehrere Aggregationsfunktionen gleichzeitig auf verschiedene Spalten anwenden willst. groupby, agg und unstack zu verketten führt schnell zu fragilem Code, der bricht, sobald sich die Datenform ändert.
Die Funktion pandas pivot_table bringt die volle Power von Excel-Pivot-Tabellen nach Python – mit einer sauberen, deklarativen API. Ein einziger Funktionsaufruf übernimmt Gruppierung, Aggregation, mehrstufige Indizes, Zwischensummen und den Umgang mit fehlenden Werten. Dieser Guide erklärt jeden Parameter, zeigt praxisnahe Beispiele und vergleicht pivot_table mit groupby, pivot und crosstab, damit du genau weißt, welches Werkzeug du wann einsetzen solltest.
Was pd.pivot_table() macht
pd.pivot_table() erstellt aus einem DataFrame eine Spreadsheet-ähnliche Zusammenfassungstabelle. Du legst fest, welche Spalten als Zeilenbeschriftungen (index) dienen, welche als Spaltenüberschriften, welche Werte aggregiert werden sollen und welche Aggregationsfunktion angewendet wird. Das Ergebnis ist ein neuer DataFrame, in dem jede Zelle eine Kennzahl (Summary Statistic) enthält.
Hier ein einfaches Vorher-nachher:
Rohdaten:
| region | product | revenue |
|---|---|---|
| North | Widget | 1200 |
| North | Gadget | 800 |
| South | Widget | 1500 |
| South | Gadget | 950 |
| North | Widget | 1400 |
| South | Widget | 1600 |
Pivot-Tabelle (Summe von revenue nach region und product):
| region | Gadget | Widget |
|---|---|---|
| North | 800 | 2600 |
| South | 950 | 3100 |
Jede Zelle enthält die Summe des Umsatzes für diese Kombination aus Region und Produkt.
pd.pivot_table() Syntax und Parameter
pd.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean',
fill_value=None, margins=False, dropna=True, margins_name='All',
observed=False, sort=True)Parameter-Referenz
| Parameter | Beschreibung | Standard |
|---|---|---|
data | Der DataFrame, der zusammengefasst werden soll | Erforderlich |
values | Spalte(n), die aggregiert werden sollen | None (alle numerischen Spalten) |
index | Spalte(n) als Zeilenlabels | None |
columns | Spalte(n) als Spaltenüberschriften | None |
aggfunc | Aggregationsfunktion(en): 'mean', 'sum', 'count', 'min', 'max' oder eine Funktion/dict/list | 'mean' |
fill_value | Wert zum Ersetzen von NaN im Ergebnis | None |
margins | Zeilen-/Spaltentotale hinzufügen (Zwischensummen) | False |
margins_name | Name für die Totals-Zeile/Spalte | 'All' |
dropna | Spalten ausschließen, deren Einträge vollständig NaN sind | True |
observed | Bei kategorialen Spalten nur beobachtete Kategorien anzeigen | False |
sort | Ergebnis sortieren | True |
Beispieldaten für alle Beispiele
Jedes Beispiel unten verwendet dieses Sales-Dataset:
import pandas as pd
import numpy as np
sales = pd.DataFrame({
'date': pd.to_datetime(['2025-01-15', '2025-01-20', '2025-02-10', '2025-02-18',
'2025-01-12', '2025-02-22', '2025-01-25', '2025-02-14',
'2025-01-30', '2025-02-05', '2025-01-18', '2025-02-28']),
'region': ['North', 'North', 'North', 'North', 'South', 'South',
'South', 'South', 'East', 'East', 'East', 'East'],
'product': ['Widget', 'Gadget', 'Widget', 'Gadget',
'Widget', 'Gadget', 'Widget', 'Gadget',
'Widget', 'Gadget', 'Widget', 'Gadget'],
'salesperson': ['Alice', 'Alice', 'Bob', 'Bob',
'Charlie', 'Charlie', 'Diana', 'Diana',
'Eve', 'Eve', 'Frank', 'Frank'],
'revenue': [1200, 800, 1400, 850, 1500, 950, 1100, 780, 1300, 900, 1250, 870],
'units': [10, 8, 12, 9, 15, 10, 11, 8, 13, 9, 12, 9]
})
print(sales)Einfache Pivot-Tabelle: Summe des Umsatzes nach Region
table = pd.pivot_table(sales, values='revenue', index='region', aggfunc='sum')
print(table)Output:
revenue
region
East 4320
North 4250
South 4330Das ist äquivalent zu sales.groupby('region')['revenue'].sum(), liefert aber einen DataFrame statt einer Series.
Spaltenüberschriften hinzufügen
Füge den Parameter columns hinzu, um die Zusammenfassung nach einer zweiten Variable aufzuschlüsseln:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum')
print(table)Output:
product Gadget Widget
region
East 1770 2550
North 1650 2600
South 1730 2600Jetzt zeigt jede Zelle den Gesamtumsatz für ein bestimmtes Region-Produkt-Paar.
Mehrere Aggregationsfunktionen
Übergebe eine Liste von Funktionen an aggfunc, um mehrere Kennzahlen auf einmal zu berechnen:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc=['sum', 'mean', 'count'])
print(table)Output:
sum mean count
product Gadget Widget Gadget Widget Gadget Widget
region
East 1770 2550 885.0 1275.0 2 2
North 1650 2600 825.0 1300.0 2 2
South 1730 2600 865.0 1300.0 2 2Das Ergebnis hat einen MultiIndex in den Spalten: oben die Aggregationsfunktion, darunter das Produkt.
Unterschiedliche Aggregationsfunktionen pro Spalte
Nutze ein Dictionary für aggfunc, um je Werte-Spalte unterschiedliche Funktionen anzuwenden:
table = pd.pivot_table(sales, values=['revenue', 'units'], index='region',
columns='product',
aggfunc={'revenue': 'sum', 'units': 'mean'})
print(table)Output:
revenue units
product Gadget Widget Gadget Widget
region
East 1770 2550 9.0 12.5
North 1650 2600 8.5 11.0
South 1730 2600 9.0 13.0Der Umsatz wird summiert, während units gemittelt werden – genau wie in einer Excel-Pivot-Tabelle mit unterschiedlichen Zusammenfassungsfunktionen pro Feld.
Zwischensummen mit margins hinzufügen
Der Parameter margins fügt eine Zeile und eine Spalte mit den Gesamtsummen hinzu:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum', margins=True)
print(table)Output:
product Gadget Widget All
region
East 1770 2550 4320
North 1650 2600 4250
South 1730 2600 4330
All 5150 7750 12900Die All-Zeile zeigt den Gesamtumsatz pro Produkt. Die All-Spalte zeigt den Gesamtumsatz pro Region. Die Zelle unten rechts ist die Gesamtsumme.
Du kannst das Label mit margins_name anpassen:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum',
margins=True, margins_name='Total')
print(table)Fehlende Werte mit fill_value behandeln
Wenn bestimmte Kombinationen in deinen Daten nicht vorkommen, enthält die Pivot-Tabelle NaN. Mit fill_value ersetzt du sie:
# Remove one row to create a missing combination
sales_missing = sales.drop(index=0)
table = pd.pivot_table(sales_missing, values='revenue', index='region',
columns='product', aggfunc='sum', fill_value=0)
print(table)Das ersetzt NaN durch 0, was übersichtlicher ist und Probleme in nachgelagerten Berechnungen vermeidet.
Multi-Level Index (Zeilen-Gruppierung)
Übergebe eine Liste von Spalten an index, um hierarchische Zeilenlabels zu erstellen:
table = pd.pivot_table(sales, values='revenue',
index=['region', 'salesperson'],
columns='product', aggfunc='sum')
print(table)Output:
product Gadget Widget
region salesperson
East Eve 900.0 1300.0
Frank 870.0 1250.0
North Alice 800.0 1200.0
Bob 850.0 1400.0
South Charlie 950.0 1500.0
Diana 780.0 1100.0Jede Verkäuferperson ist unter ihrer Region verschachtelt – ideal für eine Drill-down-Sicht auf die Daten.
Multi-Level Spalten
Analog kannst du bei columns eine Liste für hierarchische Spaltenüberschriften übergeben:
sales['month'] = sales['date'].dt.month_name()
table = pd.pivot_table(sales, values='revenue', index='region',
columns=['product', 'month'], aggfunc='sum', fill_value=0)
print(table)Das erzeugt einen zweistufigen Spaltenheader: oben product, darunter month.
Eigene Aggregationsfunktionen verwenden
Du kannst jede Callable an aggfunc übergeben – inklusive Lambda-Funktionen und NumPy-Funktionen:
# Range (max - min) of revenue by region
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc=lambda x: x.max() - x.min())
print(table)Output:
product Gadget Widget
region
East 30 50
North 50 200
South 170 400Weitere nützliche Custom-Aggregationen:
# Coefficient of variation
table = pd.pivot_table(sales, values='revenue', index='region',
aggfunc=lambda x: x.std() / x.mean() * 100)Praxisbeispiel: Analyse von Studentennoten
students = pd.DataFrame({
'student': ['Alice', 'Alice', 'Alice', 'Bob', 'Bob', 'Bob',
'Charlie', 'Charlie', 'Charlie', 'Diana', 'Diana', 'Diana'],
'subject': ['Math', 'Science', 'English'] * 4,
'semester': ['Fall', 'Fall', 'Fall', 'Fall', 'Fall', 'Fall',
'Spring', 'Spring', 'Spring', 'Spring', 'Spring', 'Spring'],
'score': [92, 88, 95, 78, 85, 72, 90, 93, 88, 85, 79, 91]
})
# Average score by subject and semester
table = pd.pivot_table(students, values='score', index='subject',
columns='semester', aggfunc='mean', margins=True)
print(table.round(1))Output:
semester Fall Spring All
subject
English 83.5 89.5 86.5
Math 85.0 87.5 86.2
Science 86.5 86.0 86.2
All 85.0 87.7 86.3Das zeigt sofort, dass die Durchschnittswerte im Spring-Semester insgesamt etwas höher sind – mit der größten Verbesserung in English.
Praxisbeispiel: Monatlicher Sales-Report
# Create a monthly sales summary
sales['month'] = sales['date'].dt.strftime('%Y-%m')
report = pd.pivot_table(sales, values=['revenue', 'units'],
index='region', columns='month',
aggfunc={'revenue': 'sum', 'units': 'sum'},
margins=True, fill_value=0)
print(report)Das erzeugt denselben monatlichen Summary-Report, den du auch in Excel bauen würdest – inklusive Totals pro Region und Monat.
pivot_table vs pivot vs groupby vs crosstab
Diese vier Funktionen überschneiden sich in ihren Möglichkeiten, aber jede hat einen klaren Use Case:
| Feature | pivot_table() | pivot() | groupby() | crosstab() |
|---|---|---|---|---|
| Aggregation | Ja (jede Funktion) | Nein (wirft Fehler bei Duplikaten) | Ja (jede Funktion) | Ja (begrenzt) |
| Handles duplicates | Ja, über aggfunc | Nein | Ja | Ja |
| Subtotals (margins) | Ja | Nein | Nein (manuell) | Ja |
| Fill missing values | Ja (fill_value) | Nein | Nein | Ja (fill_value) |
| Input | DataFrame | DataFrame | DataFrame | Series/arrays |
| Output | DataFrame | DataFrame | DataFrame/Series | DataFrame |
| Multi-level index | Ja | Ja | Ja | Ja |
| Best for | Daten mit Aggregation zusammenfassen | Eindeutige Key-Value-Daten umformen | Flexible gruppierte Analysen | Häufigkeitstabellen |
| Default function | mean | N/A | N/A | count |
Wann du was verwendest
Nutze pivot_table(), wenn du Excel-ähnliche Zusammenfassungen mit Aggregation, Totals/Zwischensummen oder mehreren Aggregationsfunktionen brauchst. Das ist die leistungsstärkste und lesbarste Option für Summary-Tabellen.
Nutze pivot(), wenn deine Daten eindeutige Kombinationen aus index- und column-Werten haben und du nur umformen (reshape) willst – ohne Aggregation. Es ist schneller als pivot_table(), weil der Aggregationsschritt entfällt.
Nutze groupby(), wenn du gruppierte Berechnungen brauchst, aber kein Wide-Format als Ergebnis. groupby liefert standardmäßig Long-Format. Ein pivot_table-ähnliches Ergebnis geht mit groupby().unstack(), aber pivot_table ist meist besser lesbar.
Nutze crosstab(), wenn du Häufigkeitstabellen oder Kreuztabellen (Cross-Tabulations) kategorialer Variablen berechnest. crosstab() akzeptiert Series oder Arrays direkt (nicht nur DataFrames) und zählt standardmäßig.
Äquivalenz-Beispiel
Diese drei Zeilen erzeugen dasselbe Ergebnis:
# pivot_table approach
result1 = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum')
# groupby + unstack approach
result2 = sales.groupby(['region', 'product'])['revenue'].sum().unstack()
# Both produce the same table
print(result1.equals(result2)) # TrueDie pivot_table-Variante ist besser lesbar – besonders, wenn du margins, fill values oder mehrere Aggregationsfunktionen hinzufügst.
MultiIndex-Spalten abflachen (Flattening)
Wenn du eine Pivot-Tabelle mit mehreren Aggregationsfunktionen erzeugst, erhältst du oft MultiIndex-Spalten, mit denen man schwer arbeiten kann:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc=['sum', 'mean'])
# Flatten the column MultiIndex
table.columns = ['_'.join(col).strip() for col in table.columns.values]
print(table)Output:
sum_Gadget sum_Widget mean_Gadget mean_Widget
region
East 1770 2550 885.0 1275.0
North 1650 2600 825.0 1300.0
South 1730 2600 865.0 1300.0Jetzt sind die Spalten flache Strings und lassen sich leichter referenzieren.
Pivot-Tabellen sortieren und filtern
Pivot-Tabellen sind normale DataFrames – du kannst sie also sortieren und filtern:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum', margins=True)
# Sort by total revenue (All column), descending
sorted_table = table.sort_values('All', ascending=False)
print(sorted_table)
# Filter to show only regions with Widget revenue > 2500
filtered = table[table['Widget'] > 2500]
print(filtered)Pivot-Tabellen exportieren
Speichere deine Pivot-Tabelle nach Excel (wo Stakeholder sie erwarten) oder als CSV:
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum', margins=True)
# Export to Excel
table.to_excel('sales_pivot.xlsx', sheet_name='Revenue Summary')
# Export to CSV
table.to_csv('sales_pivot.csv')Performance-Tipps
pivot_table() ruft intern groupby auf, daher ist die Performance ähnlich. Für große Datensätze:
| Dataset Size | Expected Time |
|---|---|
| 100K rows, 2 group cols | ~5 ms |
| 1M rows, 2 group cols | ~50 ms |
| 10M rows, 3 group cols | ~500 ms |
Optimierungsstrategien:
- Daten vor dem Pivot reduzieren – filtere Zeilen und wähle nur die benötigten Spalten aus, bevor du
pivot_table()aufrufst. - Categorical dtypes verwenden – wandle String-Spalten in den
categorydtype um, um schneller zu gruppieren. - Lambda aggfuncs vermeiden – eingebaute String-Namen (
'sum','mean') nutzen optimierten C-Code. Lambda-Funktionen fallen auf langsamere Python-Loops zurück.
# Faster: use categorical dtypes
sales['region'] = sales['region'].astype('category')
sales['product'] = sales['product'].astype('category')
# Faster: use string name instead of lambda
table = pd.pivot_table(sales, values='revenue', index='region',
columns='product', aggfunc='sum') # 'sum' is optimizedPivot-Tabellen mit PyGWalker visualisieren
Während pd.pivot_table() großartig für numerische Zusammenfassungen ist, willst du manchmal Muster in deinen Daten interaktiv visualisieren. PyGWalker (opens in a new tab) ist eine Open-Source-Python-Library, mit der du Pivot-Tabellen, Balkendiagramme, Heatmaps und mehr über ein visuelles Drag-and-drop-Interface erstellen kannst – nach dem initialen Setup ohne weiteren Code.
import pandas as pd
import pygwalker as pyg
sales = pd.DataFrame({
'region': ['North', 'North', 'South', 'South', 'East', 'East'] * 2,
'product': ['Widget', 'Gadget'] * 6,
'revenue': [1200, 800, 1500, 950, 1300, 900, 1400, 850, 1100, 780, 1250, 870],
'units': [10, 8, 15, 10, 13, 9, 12, 9, 11, 8, 12, 9]
})
# Launch interactive pivot table and visualization
walker = pyg.walk(sales)PyGWalker bietet dir ein Tableau-ähnliches Interface, in dem du region auf Rows, product auf Columns und revenue auf Values ziehen kannst, um visuell eine Pivot-Tabelle zu erstellen. Du kannst sofort zwischen Tabellen- und Chart-Ansicht wechseln, verschiedene Aggregationsfunktionen ausprobieren und das Ergebnis exportieren – ohne zusätzlichen Code zu schreiben.
Probiere PyGWalker in Google Colab (opens in a new tab), Kaggle (opens in a new tab), oder installiere es mit
pip install pygwalker.
FAQ
Was ist der Unterschied zwischen pivot und pivot_table in pandas?
pivot() formt Daten ohne Aggregation um – es erfordert eindeutige Kombinationen aus Index- und Spaltenwerten und wirft einen Fehler, wenn Duplikate existieren. pivot_table() kann mit Duplikaten umgehen, indem es sie mit einer Funktion wie sum oder mean aggregiert. Verwende pivot() für einfaches Reshaping und pivot_table(), wenn du Aggregation oder Totals/Zwischensummen brauchst.
Wie füge ich Totals (margins) zu einer pandas Pivot-Tabelle hinzu?
Setze margins=True im pivot_table()-Aufruf: pd.pivot_table(df, values='revenue', index='region', columns='product', aggfunc='sum', margins=True). Das fügt eine All-Zeile und -Spalte mit Zwischensummen hinzu. Passe das Label mit margins_name='Total' an.
Kann ich mehrere Aggregationsfunktionen in einer Pivot-Tabelle verwenden?
Ja. Übergib eine Liste an aggfunc: aggfunc=['sum', 'mean', 'count']. Das erzeugt einen MultiIndex-Spaltenheader mit einer Ebene für die Funktion und einer Ebene für die Values-Spalten. Du kannst auch ein Dictionary übergeben, um je Spalte unterschiedliche Funktionen zu nutzen: aggfunc={'revenue': 'sum', 'units': 'mean'}.
Worin unterscheidet sich pivot_table von groupby in pandas?
Beide aggregieren Daten, aber pivot_table() erzeugt ein Wide-Format-Ergebnis (mit Spaltenüberschriften aus einer der Gruppierungsvariablen), während groupby() standardmäßig Long-Format liefert. pivot_table() unterstützt außerdem margins (Zwischensummen) und fill values nativ. Intern verwendet pivot_table() groupby().
Wie gehe ich mit NaN-Werten in einer Pivot-Tabelle um?
Verwende den Parameter fill_value, um NaN durch einen bestimmten Wert zu ersetzen: pd.pivot_table(df, ..., fill_value=0). Der Parameter dropna=True (Standard) schließt Spalten aus, deren Einträge vollständig NaN sind.
Kann ich eine Pivot-Tabelle mit Prozentwerten erstellen?
Ja. Erstelle zuerst die Pivot-Tabelle mit Counts oder Summen und teile dann durch die Gesamtsumme. Alternativ kannst du bei pd.crosstab() normalize für prozentbasierte Kreuztabellen verwenden. Für Pivot-Tabellen berechnest du Prozente manuell: table = table.div(table.sum(axis=1), axis=0) * 100.
Fazit
Die pandas-Funktion pivot_table() ist das vielseitigste Werkzeug, um Summary-Tabellen in Python zu erstellen. Die wichtigsten Punkte:
- Nutze
values,indexundcolumns, um festzulegen, was zusammengefasst wird, wie Zeilen gruppiert werden und wie Spalten gruppiert werden. - Nutze
aggfunc, um die Aggregationsfunktion festzulegen. Übergib eine Liste für mehrere Funktionen oder ein Dictionary für Funktionen pro Spalte. - Nutze
margins=True, um Zwischensummen hinzuzufügen – das Pendant zu „Grand Total“ in Excel. - Nutze
fill_value, um fehlende Kombinationen durch einen Standardwert zu ersetzen (typischerweise 0). - Bevorzuge
pivot_table()gegenübergroupby().unstack()wegen der Lesbarkeit, besonders wenn du margins oder fill values brauchst. - Bevorzuge
pivot()gegenüberpivot_table(), wenn deine Daten eindeutige Key-Kombinationen haben und du keine Aggregation brauchst. - Bevorzuge
crosstab()für einfache Häufigkeitstabellen kategorialer Variablen.
Für die interaktive Exploration deiner Pivot-Tabellen bietet PyGWalker (opens in a new tab) ein visuelles Drag-and-drop-Interface, das das Excel-Pivot-Tabellen-Erlebnis in Jupyter Notebook nachbildet.