Pandas Melt: Wide Daten in Long-Format umformen (Kompletter Leitfaden)
Updated on
Du hast eine Tabelle, in der jeder Monat eine eigene Spalte ist – Januar, Februar, März, bis hin zu Dezember. Zwölf Spalten mit Umsatzwerten, und du musst eine Zeitreihe plotten, ein groupby ausführen oder die Daten in ein Machine-Learning-Modell einspeisen. Keine dieser Operationen funktioniert gut mit Daten im Wide-Format. Du brauchst eine Spalte für den Monatsnamen und eine Spalte für den Umsatzwert. Diese Transformation – Spalten in Zeilen zu verwandeln – ist genau das, was pandas melt macht.
Das Problem wird schnell größer. Wide-Datensätze mit Dutzenden oder Hunderten Spalten sind typisch bei Umfragedaten, Sensor-Messreihen, Finanzreports und pivotierten Exporten aus Excel oder SQL. Sie manuell umzustrukturieren ist mühsam und fehleranfällig. Jede zusätzliche Spalte, die du entpivotieren musst, bedeutet mehr Boilerplate-Code, wenn du es ohne das richtige Tool versuchst.
Die Funktion pd.melt() löst das mit einem einzigen Aufruf. Sie nimmt einen Wide-DataFrame und „schmilzt“ ihn ins Long-Format, indem sie ausgewählte Spalten in Zeilen umwandelt, während deine Identifier-Spalten unverändert erhalten bleiben. Dieser Leitfaden deckt die komplette Syntax ab, jeden Parameter, praktische Beispiele aus realen Szenarien sowie Vergleiche mit verwandten Reshape-Funktionen wie pivot, stack und wide_to_long.
Was pd.melt() macht
pd.melt() entpivotiert (unpivot) einen DataFrame vom Wide-Format ins Long-Format. Im Wide-Format hat jede Variable ihre eigene Spalte. Im Long-Format (auch „tidy“ Format genannt) gibt es eine Spalte für Variablennamen und eine Spalte für Werte.
Hier ist die konzeptionelle Transformation:
Wide-Format (vor melt):
| student | math | science | english |
|---|---|---|---|
| Alice | 90 | 85 | 88 |
| Bob | 78 | 92 | 80 |
Long-Format (nach melt):
| student | subject | score |
|---|---|---|
| Alice | math | 90 |
| Alice | science | 85 |
| Alice | english | 88 |
| Bob | math | 78 |
| Bob | science | 92 |
| Bob | english | 80 |
Die Spalte student bleibt als Identifier erhalten, während die drei Fach-Spalten in zwei Spalten „geschmolzen“ werden: eine mit dem Fachnamen und eine mit der Punktzahl.
pd.melt() Syntax und Parameter
pd.melt(frame, id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)Du kannst es auch als Methode direkt auf dem DataFrame aufrufen:
df.melt(id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)Parameter-Referenz
| Parameter | Beschreibung | Standard |
|---|---|---|
frame | Der zu meltende DataFrame (nicht nötig bei df.melt()) | Erforderlich |
id_vars | Spalte(n), die als Identifier-Variablen behalten werden (werden nicht gemolten) | None |
value_vars | Spalte(n), die in Zeilen entpivotiert werden. Falls weggelassen, werden alle Spalten verwendet, die nicht in id_vars sind | None |
var_name | Name der neuen Spalte, die die ursprünglichen Spaltennamen enthält | 'variable' |
value_name | Name der neuen Spalte, die die Werte enthält | 'value' |
col_level | Falls die Spalten ein MultiIndex sind: welches Level gemolten wird | None |
ignore_index | Wenn True, bekommt das Ergebnis einen neuen Integer-Index. Wenn False, bleibt der ursprüngliche Index erhalten | True |
Basisbeispiel: Noten von Schülern
Starte mit dem Notenbeispiel von oben:
import pandas as pd
grades = pd.DataFrame({
'student': ['Alice', 'Bob', 'Charlie'],
'math': [90, 78, 85],
'science': [85, 92, 88],
'english': [88, 80, 91]
})
long = pd.melt(grades, id_vars=['student'], value_vars=['math', 'science', 'english'],
var_name='subject', value_name='score')
print(long)Output:
student subject score
0 Alice math 90
1 Bob math 78
2 Charlie math 85
3 Alice science 85
4 Bob science 92
5 Charlie science 88
6 Alice english 88
7 Bob english 80
8 Charlie english 91Jede Zeile repräsentiert jetzt eine Kombination aus Schüler und Fach. Aus dem ursprünglichen 3x4-DataFrame (3 Zeilen, 4 Spalten) wird ein 9x3-DataFrame (9 Zeilen, 3 Spalten).
value_vars weglassen
Wenn du value_vars weglässt, meltet pandas jede Spalte, die nicht in id_vars aufgeführt ist:
long = grades.melt(id_vars=['student'], var_name='subject', value_name='score')
print(long)Das erzeugt das gleiche Ergebnis wie im vorherigen Beispiel. value_vars wegzulassen ist praktisch, wenn du alle Nicht-Identifier-Spalten melten möchtest.
Melten ohne id_vars
Du kannst auch melten, ohne Identifier-Spalten anzugeben. Dann wird jede Spalte Teil des Variable/Value-Paars:
temperatures = pd.DataFrame({
'Jan': [30, 28],
'Feb': [32, 31],
'Mar': [45, 42]
})
long = temperatures.melt(var_name='month', value_name='temp_f')
print(long)Output:
month temp_f
0 Jan 30
1 Jan 28
2 Feb 32
3 Feb 31
4 Mar 45
5 Mar 42Das ist nützlich, wenn jede Spalte eine Messung ist und es keinen Identifier gibt, den du erhalten musst.
Mehrere Identifier-Spalten
Reale Datensätze haben oft mehr als einen Identifier. Du kannst eine Liste von Spaltennamen an id_vars übergeben:
sales = pd.DataFrame({
'region': ['North', 'South', 'North', 'South'],
'product': ['Widget', 'Widget', 'Gadget', 'Gadget'],
'q1_revenue': [1200, 1500, 800, 950],
'q2_revenue': [1400, 1600, 900, 1100],
'q3_revenue': [1100, 1450, 850, 1000],
'q4_revenue': [1500, 1700, 1000, 1200]
})
long_sales = sales.melt(
id_vars=['region', 'product'],
var_name='quarter',
value_name='revenue'
)
print(long_sales)Output:
region product quarter revenue
0 North Widget q1_revenue 1200
1 South Widget q1_revenue 1500
2 North Gadget q1_revenue 800
3 South Gadget q1_revenue 950
4 North Widget q2_revenue 1400
5 South Widget q2_revenue 1600
6 North Gadget q2_revenue 900
7 South Gadget q2_revenue 1100
8 North Widget q3_revenue 1100
9 South Widget q3_revenue 1450
10 North Gadget q3_revenue 850
11 South Gadget q3_revenue 1000
12 North Widget q4_revenue 1500
13 South Widget q4_revenue 1700
14 North Gadget q4_revenue 1000
15 South Gadget q4_revenue 1200Sowohl region als auch product bleiben für jede Zeile erhalten. Die vier Quartals-Spalten werden in zwei Spalten zusammengeführt.
Aufräumen nach dem Melt
Nach dem Melten enthält die Spalte variable oft Strings, die du bereinigen möchtest. Im Beispiel oben hat die Quartalsspalte Werte wie q1_revenue statt nur Q1. Mit String-Operationen kannst du das korrigieren:
long_sales['quarter'] = long_sales['quarter'].str.replace('_revenue', '').str.upper()
print(long_sales.head())Output:
region product quarter revenue
0 North Widget Q1 1200
1 South Widget Q1 1500
2 North Gadget Q1 800
3 South Gadget Q1 950
4 North Widget Q2 1400Nur ausgewählte Spalten melten
Manchmal willst du nur eine Teilmenge der Spalten melten. Gib sie in value_vars explizit an:
survey = pd.DataFrame({
'respondent': ['R1', 'R2', 'R3'],
'age': [25, 34, 42],
'q1_satisfaction': [4, 5, 3],
'q2_satisfaction': [3, 4, 5],
'q3_satisfaction': [5, 3, 4],
'income': [50000, 75000, 60000]
})
# Only melt the satisfaction columns, keep age and income as identifiers
long_survey = survey.melt(
id_vars=['respondent', 'age', 'income'],
value_vars=['q1_satisfaction', 'q2_satisfaction', 'q3_satisfaction'],
var_name='question',
value_name='rating'
)
print(long_survey)Output:
respondent age income question rating
0 R1 25 50000 q1_satisfaction 4
1 R2 34 75000 q1_satisfaction 5
2 R3 42 60000 q1_satisfaction 3
3 R1 25 50000 q2_satisfaction 3
4 R2 34 75000 q2_satisfaction 4
5 R3 42 60000 q2_satisfaction 5
6 R1 25 50000 q3_satisfaction 5
7 R2 34 75000 q3_satisfaction 3
8 R3 42 60000 q3_satisfaction 4Die Spalte income bleibt als Identifier erhalten, obwohl sie nicht Teil der gemolten Spalten ist.
Praxisbeispiel: Zeitreihen-Daten
Finanz- und Wirtschaftsdaten kommen häufig im Wide-Format, bei dem Datumswerte als Spaltenüberschriften vorliegen. Durch Melten wird daraus eine plottbare Zeitreihe:
import pandas as pd
gdp = pd.DataFrame({
'country': ['USA', 'UK', 'Germany'],
'2020': [20.94, 2.71, 3.89],
'2021': [23.00, 3.12, 4.26],
'2022': [25.46, 3.07, 4.07],
'2023': [27.36, 3.33, 4.46]
})
gdp_long = gdp.melt(id_vars=['country'], var_name='year', value_name='gdp_trillion_usd')
gdp_long['year'] = gdp_long['year'].astype(int)
gdp_long = gdp_long.sort_values(['country', 'year']).reset_index(drop=True)
print(gdp_long)Output:
country year gdp_trillion_usd
0 Germany 2020 3.89
1 Germany 2021 4.26
2 Germany 2022 4.07
3 Germany 2023 4.46
4 UK 2020 2.71
5 UK 2021 3.12
6 UK 2022 3.07
7 UK 2023 3.33
8 USA 2020 20.94
9 USA 2021 23.00
10 USA 2022 25.46
11 USA 2023 27.36Jetzt kannst du das BIP leicht über die Zeit plotten, nach Ländern gruppieren oder Year-over-Year-Wachstum berechnen.
Melten mit MultiIndex-Spalten
Wenn dein DataFrame mehrstufige Spalten-Header hat, nutze den Parameter col_level, um festzulegen, welches Level gemolten werden soll:
arrays = [['score', 'score', 'attendance', 'attendance'],
['midterm', 'final', 'midterm', 'final']]
columns = pd.MultiIndex.from_arrays(arrays, names=['metric', 'exam'])
data = pd.DataFrame([[85, 90, 95, 100], [78, 82, 90, 88]],
index=['Alice', 'Bob'], columns=columns)
# Melt the top level
melted = data.melt(col_level=0, var_name='metric', value_name='value', ignore_index=False)
print(melted)Für komplexere Multi-Level-Szenarien musst du die Spalten ggf. vorher flatten, z. B. mit droplevel() oder indem du Levels per Unterstrich zusammenfügst, bevor du melt anwendest.
Melt vs Pivot: Inverse Operationen
melt() und pivot() sind inverse Operationen. Melt wandelt Wide zu Long. Pivot wandelt Long zu Wide.
import pandas as pd
# Start wide
wide = pd.DataFrame({
'name': ['Alice', 'Bob'],
'math': [90, 78],
'science': [85, 92]
})
# Melt: wide -> long
long = wide.melt(id_vars='name', var_name='subject', value_name='score')
print("Long format:")
print(long)
# Pivot: long -> wide (round-trip)
back_to_wide = long.pivot(index='name', columns='subject', values='score').reset_index()
back_to_wide.columns.name = None
print("\nBack to wide format:")
print(back_to_wide)Output:
Long format:
name subject score
0 Alice math 90
1 Bob math 78
2 Alice science 85
3 Bob science 92
Back to wide format:
name math science
0 Alice 90 85
1 Bob 78 92Wichtiger Unterschied: pivot() erfordert eindeutige Kombinationen aus Index und Spalten. Wenn deine Long-Daten Duplikate enthalten, verwende stattdessen pivot_table() mit einer Aggregationsfunktion.
Melt vs Stack vs wide_to_long
Pandas bietet mehrere Funktionen zum Reshaping. Hier ist, wann du welche verwenden solltest:
| Function | Direction | Best For | Key Difference |
|---|---|---|---|
melt() | wide to long | Bestimmte Spalten in Zeilen entpivotieren | Spaltenbasiert; am intuitivsten für Einsteiger |
stack() | wide to long | Spalten-Level in Index-Level zusammenklappen | Indexbasiert; funktioniert gut mit MultiIndex |
wide_to_long() | wide to long | Spalten mit gemeinsamem Prefix und numerischem Suffix (z. B. score1, score2) | Parst Stub-Namen automatisch |
pivot() | long to wide | Werte in Spalten verteilen (eindeutige Keys) | Invers zu melt() |
unstack() | long to wide | Index-Level zu Spalten ausklappen | Invers zu stack() |
Wann du stattdessen stack() verwenden solltest
stack() arbeitet auf dem Spaltenindex und schiebt ihn in den Zeilenindex. Es ist am nützlichsten, wenn du bereits mit einem MultiIndex arbeitest und auf Index-Ebene umformen willst:
wide = pd.DataFrame({
'math': [90, 78],
'science': [85, 92]
}, index=['Alice', 'Bob'])
stacked = wide.stack()
print(stacked)Output:
Alice math 90
science 85
Bob math 78
science 92
dtype: int64Das Ergebnis ist eine Series mit MultiIndex, nicht ein DataFrame mit benannten Spalten wie bei melt(). Verwende melt(), wenn du ein sauberes DataFrame-Output mit explizit benannten Spalten willst.
Wann du wide_to_long() verwenden solltest
wide_to_long() ist für Spalten gedacht, die einem Namensmuster wie score1, score2, score3 folgen:
df = pd.DataFrame({
'student': ['Alice', 'Bob'],
'score1': [90, 78],
'score2': [85, 92],
'score3': [88, 80]
})
long = pd.wide_to_long(df, stubnames='score', i='student', j='exam_num')
print(long.reset_index())Output:
student exam_num score
0 Alice 1 90
1 Alice 2 85
2 Alice 3 88
3 Bob 1 78
4 Bob 2 92
5 Bob 3 80Nutze wide_to_long(), wenn deine Spalten ein konsistentes Prefix-Suffix-Muster haben. Andernfalls ist melt() flexibler.
Performance-Überlegungen
Für die meisten Datensätze (unter ein paar Millionen Zeilen) ist melt() schnell genug. Hier sind Benchmarks auf einem DataFrame mit 100.000 Zeilen und 50 Spalten, die gemolten werden:
| Operation | Approximate Time |
|---|---|
melt() with 50 value columns | ~15 ms |
stack() equivalent | ~10 ms |
Manual loop with concat() | ~500 ms |
Tipps für bessere Performance:
value_varsexplizit angeben – nur die Spalten zu melten, die du brauchst, ist schneller als alle zu melten.ignore_index=Trueverwenden (Standard) – den Originalindex zu behalten erzeugt Overhead.- Melten und direkt wieder pivotieren vermeiden – wenn du ein anderes Wide-Format brauchst, nutze ggf.
pivot_table()oderrename()direkt statt eines Round-Trips. - Für sehr große DataFrames (100M+ Zeilen nach dem Melt) erwäge polars oder Dask, die Lazy Evaluation und Parallelisierung bieten.
# Only melt the columns you actually need
long = df.melt(
id_vars=['id'],
value_vars=['col_a', 'col_b', 'col_c'], # Not all 50 columns
var_name='metric',
value_name='reading'
)Häufige Fehler und wie du sie behebst
1. KeyError: Spalte nicht gefunden
Das passiert, wenn ein Spaltenname in id_vars oder value_vars nicht im DataFrame existiert:
# Wrong: column name has a typo
long = df.melt(id_vars=['stduent']) # KeyError
# Fix: check column names first
print(df.columns.tolist())2. Unerwartete Duplicate Rows
Melt selbst erzeugt keine Duplikate – es erzeugt eine Zeile pro Kombination aus Identifier und Variable. Wenn du Duplikate siehst, bedeutet das, dass deine Originaldaten doppelte Identifier-Zeilen hatten:
# Check for duplicates in your id columns
print(df.duplicated(subset=['student']).sum())3. Gemischte Datentypen in der Value-Spalte
Wenn du Spalten mit unterschiedlichen dtypes meltst (z. B. einige int64, andere float64), castet pandas die Value-Spalte auf den allgemeinsten Typ. Wenn du eine Mischung aus numerischen und String-Spalten meltst, wird die Value-Spalte zum dtype object:
df = pd.DataFrame({
'id': [1, 2],
'score': [90, 85],
'grade': ['A', 'B']
})
long = df.melt(id_vars='id')
print(long.dtypes)
# variable object
# value object <-- both score and grade become objectUm das zu vermeiden, melte numerische und String-Spalten separat.
Visualisiere gemoltete Daten mit PyGWalker
Nachdem du deine Daten vom Wide- ins Long-Format umgeformt hast, ist der nächste sinnvolle Schritt, das Ergebnis visuell zu erkunden – Verteilungen prüfen, Gruppen vergleichen oder Ausreißer entdecken. PyGWalker (opens in a new tab) ist eine Open-Source-Python-Library, die jeden pandas DataFrame in eine interaktive, Tableau-ähnliche Visual-Exploration-Oberfläche in Jupyter Notebook verwandelt.
import pandas as pd
import pygwalker as pyg
# Melt your wide data into long format
grades = pd.DataFrame({
'student': ['Alice', 'Bob', 'Charlie', 'Diana'],
'math': [90, 78, 85, 92],
'science': [85, 92, 88, 79],
'english': [88, 80, 91, 84]
})
long = grades.melt(id_vars='student', var_name='subject', value_name='score')
# Launch interactive visualization
walker = pyg.walk(long)Mit PyGWalker kannst du subject auf die x-Achse und score auf die y-Achse ziehen und anschließend nach student einfärben, um Leistungen über Fächer hinweg sofort zu vergleichen – ganz ohne Chart-Code. Es unterstützt Bar Charts, Scatter Plots, Box Plots und mehr, alles per Drag-and-drop.
Probiere PyGWalker in Google Colab (opens in a new tab), Kaggle (opens in a new tab) aus oder installiere es mit
pip install pygwalker.
FAQ
Was macht pandas melt?
Pandas melt() formt einen DataFrame vom Wide-Format ins Long-Format um. Es nimmt Spalten und macht daraus Zeilen und erzeugt zwei neue Spalten: eine für die ursprünglichen Spaltennamen (variable) und eine für die Werte. Das wird auch „unpivoting“ genannt.
Was ist der Unterschied zwischen melt und pivot in pandas?
melt() konvertiert Wide-Format zu Long-Format (Spalten werden zu Zeilen). pivot() macht das Gegenteil – es konvertiert Long-Format zu Wide-Format (Zeilen werden zu Spalten). Es sind inverse Operationen. Wenn du einen DataFrame meltst und dann das Ergebnis mit denselben Parametern pivotierst, erhältst du den ursprünglichen DataFrame zurück.
Wann sollte ich melt vs stack in pandas verwenden?
Verwende melt(), wenn du einen sauberen DataFrame mit benannten Spalten und expliziter Kontrolle darüber möchtest, welche Spalten entpivotiert werden. Verwende stack(), wenn du mit MultiIndex-Spalten arbeitest und Spalten-Level in den Zeilenindex schieben willst. melt() ist für Einsteiger intuitiver; stack() ist mächtiger für hierarchisches Reshaping.
Wie melte ich mehrere Spalten in pandas?
Gib eine Liste von Spaltennamen an den Parameter value_vars weiter: df.melt(id_vars=['id'], value_vars=['col_a', 'col_b', 'col_c']). Alle aufgelisteten Spalten werden in Zeilen entpivotiert. Wenn du value_vars weglässt, meltet pandas alle Spalten, die nicht in id_vars sind.
Kann ich einen DataFrame mit doppelten Spaltennamen melten?
Pandas wird den DataFrame melten, aber das Ergebnis kann verwirrend sein, weil die Spalte variable dann doppelte Werte enthält. Benenne die doppelten Spalten vorher um, z. B. mit df.columns = [...] oder df.rename(), um Mehrdeutigkeit zu vermeiden.
Wie mache ich eine Melt-Operation in pandas rückgängig?
Verwende pivot() oder pivot_table(), um die gemolteten (Long-)Daten zurück ins Wide-Format zu konvertieren: long.pivot(index='id', columns='variable', values='value'). Nutze pivot_table(), wenn es doppelte Index-Spalten-Kombinationen gibt, die eine Aggregation erfordern.
Fazit
Die pandas-Funktion melt() ist der Standardweg, um Wide-Format-DataFrames in Python ins Long- (tidy-)Format umzuwandeln. Die wichtigsten Punkte:
- Nutze
id_vars, um festzulegen, welche Spalten als Identifier erhalten bleiben. - Nutze
value_vars, um zu steuern, welche Spalten gemolten werden. Lasse es weg, um alles außer den Identifiern zu melten. - Nutze
var_nameundvalue_name, um den Output-Spalten sinnvolle Namen zu geben. - Melt und Pivot sind invers – nutze
melt()für Wide-to-Long undpivot()für Long-to-Wide. - Wähle
melt()stattstack(), wenn du einen flachen DataFrame mit expliziten Spaltennamen statt einer MultiIndex-Series willst. - Nach dem Melten bereinigen – verwende String-Methoden auf der Variable-Spalte, um Prefixe/Suffixe zu entfernen oder Werte zu formatieren.
Nach dem Reshaping helfen Tools wie PyGWalker (opens in a new tab), das Ergebnis visuell zu erkunden, ohne Chart-Code zu schreiben – das macht den Analyse-Workflow schneller und intuitiver.