Skip to content

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):

studentmathscienceenglish
Alice908588
Bob789280

Long-Format (nach melt):

studentsubjectscore
Alicemath90
Alicescience85
Aliceenglish88
Bobmath78
Bobscience92
Bobenglish80

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

ParameterBeschreibungStandard
frameDer zu meltende DataFrame (nicht nötig bei df.melt())Erforderlich
id_varsSpalte(n), die als Identifier-Variablen behalten werden (werden nicht gemolten)None
value_varsSpalte(n), die in Zeilen entpivotiert werden. Falls weggelassen, werden alle Spalten verwendet, die nicht in id_vars sindNone
var_nameName der neuen Spalte, die die ursprünglichen Spaltennamen enthält'variable'
value_nameName der neuen Spalte, die die Werte enthält'value'
col_levelFalls die Spalten ein MultiIndex sind: welches Level gemolten wirdNone
ignore_indexWenn True, bekommt das Ergebnis einen neuen Integer-Index. Wenn False, bleibt der ursprüngliche Index erhaltenTrue

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     91

Jede 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      42

Das 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     1200

Sowohl 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     1400

Nur 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       4

Die 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.36

Jetzt 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       92

Wichtiger 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:

FunctionDirectionBest ForKey Difference
melt()wide to longBestimmte Spalten in Zeilen entpivotierenSpaltenbasiert; am intuitivsten für Einsteiger
stack()wide to longSpalten-Level in Index-Level zusammenklappenIndexbasiert; funktioniert gut mit MultiIndex
wide_to_long()wide to longSpalten mit gemeinsamem Prefix und numerischem Suffix (z. B. score1, score2)Parst Stub-Namen automatisch
pivot()long to wideWerte in Spalten verteilen (eindeutige Keys)Invers zu melt()
unstack()long to wideIndex-Level zu Spalten ausklappenInvers 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: int64

Das 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     80

Nutze 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:

OperationApproximate Time
melt() with 50 value columns~15 ms
stack() equivalent~10 ms
Manual loop with concat()~500 ms

Tipps für bessere Performance:

  1. value_vars explizit angeben – nur die Spalten zu melten, die du brauchst, ist schneller als alle zu melten.
  2. ignore_index=True verwenden (Standard) – den Originalindex zu behalten erzeugt Overhead.
  3. Melten und direkt wieder pivotieren vermeiden – wenn du ein anderes Wide-Format brauchst, nutze ggf. pivot_table() oder rename() direkt statt eines Round-Trips.
  4. 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 object

Um 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_name und value_name, um den Output-Spalten sinnvolle Namen zu geben.
  • Melt und Pivot sind invers – nutze melt() für Wide-to-Long und pivot() für Long-to-Wide.
  • Wähle melt() statt stack(), 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.

📚