Pandas Melt : remodeler des données larges en format long (guide complet)
Updated on
Vous avez une feuille de calcul où chaque mois est une colonne séparée — January, February, March, jusqu’à December. Douze colonnes de chiffres de revenus, et vous devez tracer une série temporelle, faire un groupby ou alimenter un modèle de machine learning. Aucune de ces opérations ne fonctionne bien avec des données au format wide. Il vous faut une colonne pour le nom du mois et une colonne pour la valeur de revenu. Cette transformation — transformer des colonnes en lignes — est exactement ce que fait pandas melt.
Le problème s’aggrave vite. Les jeux de données wide avec des dizaines ou des centaines de colonnes sont courants dans les données d’enquête, les relevés de capteurs, les rapports financiers et les exports pivotés depuis Excel ou SQL. Les restructurer manuellement est fastidieux et propice aux erreurs. Chaque colonne supplémentaire à dé-pivoter implique davantage de code répétitif si vous essayez de le faire sans l’outil adapté.
La fonction pd.melt() résout cela en un seul appel. Elle prend un DataFrame au format wide et le « melt » en format long en transformant certaines colonnes en lignes, tout en conservant intactes vos colonnes d’identifiant. Ce guide couvre la syntaxe complète, chaque paramètre, des exemples pratiques issus de cas réels, ainsi que des comparaisons avec des fonctions de remodelage proches comme pivot, stack et wide_to_long.
Ce que fait pd.melt()
pd.melt() dé-pivote un DataFrame du format wide vers le format long. En format wide, chaque variable a sa propre colonne. En format long (aussi appelé format « tidy »), il y a une colonne pour les noms de variables et une colonne pour les valeurs.
Voici la transformation conceptuelle :
Format wide (avant melt) :
| student | math | science | english |
|---|---|---|---|
| Alice | 90 | 85 | 88 |
| Bob | 78 | 92 | 80 |
Format long (après melt) :
| student | subject | score |
|---|---|---|
| Alice | math | 90 |
| Alice | science | 85 |
| Alice | english | 88 |
| Bob | math | 78 |
| Bob | science | 92 |
| Bob | english | 80 |
La colonne student est conservée comme identifiant, tandis que les trois colonnes de matières sont « melt » en deux colonnes : l’une contenant le nom de la matière, et l’autre contenant la note.
Syntaxe et paramètres de pd.melt()
pd.melt(frame, id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)Vous pouvez aussi l’appeler comme une méthode directement sur le DataFrame :
df.melt(id_vars=None, value_vars=None, var_name=None,
value_name='value', col_level=None, ignore_index=True)Référence des paramètres
| Paramètre | Description | Valeur par défaut |
|---|---|---|
frame | Le DataFrame à « melt » (inutile si vous utilisez df.melt()) | Requis |
id_vars | Colonne(s) à conserver comme variables d’identification (non « melt ») | None |
value_vars | Colonne(s) à dé-pivoter en lignes. Si omis, toutes les colonnes non dans id_vars sont utilisées | None |
var_name | Nom de la nouvelle colonne contenant les noms de colonnes d’origine | 'variable' |
value_name | Nom de la nouvelle colonne contenant les valeurs | 'value' |
col_level | Si les colonnes sont un MultiIndex, le niveau à « melt » | None |
ignore_index | Si True, le résultat utilise un nouvel index entier. Si False, l’index d’origine est conservé | True |
Exemple de base : notes d’élèves
Repartons de l’exemple des notes d’élèves ci-dessus :
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 91Chaque ligne représente maintenant une combinaison élève-matière. Le DataFrame d’origine en 3x4 (3 lignes, 4 colonnes) devient un DataFrame 9x3 (9 lignes, 3 colonnes).
Omettre value_vars
Si vous ne renseignez pas value_vars, pandas « melt » chaque colonne qui n’est pas listée dans id_vars :
long = grades.melt(id_vars=['student'], var_name='subject', value_name='score')
print(long)Cela produit le même résultat que l’exemple précédent. Omettre value_vars est pratique quand vous voulez « melt » toutes les colonnes non-identifiantes.
Melt sans id_vars
Vous pouvez aussi effectuer un melt sans spécifier de colonnes d’identifiant. Cela met toutes les colonnes dans la paire variable/valeur :
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 42C’est utile lorsque chaque colonne est une mesure et qu’il n’y a aucun identifiant à conserver.
Plusieurs colonnes d’identifiant
Les jeux de données réels ont souvent plus d’un identifiant. Vous pouvez passer une liste de noms de colonnes à id_vars :
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 1200region et product sont tous deux conservés pour chaque ligne. Les quatre colonnes trimestrielles sont condensées en deux colonnes.
Nettoyer après un melt
Après un melt, la colonne variable contient souvent des chaînes que vous voulez nettoyer. Dans l’exemple ci-dessus, la colonne du trimestre a des valeurs comme q1_revenue au lieu de simplement Q1. Utilisez des opérations de chaîne pour corriger cela :
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 1400Melt de colonnes sélectionnées uniquement
Parfois, vous ne voulez « melt » qu’un sous-ensemble de colonnes. Spécifiez-les explicitement dans value_vars :
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 4La colonne income est conservée comme identifiant même si elle ne fait pas partie des colonnes « melt ».
Exemple concret : données de séries temporelles
Les données financières et économiques arrivent souvent en format wide avec des dates comme en-têtes de colonnes. Un melt convertit cela en une série temporelle facile à tracer :
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.36Vous pouvez maintenant facilement tracer le PIB dans le temps, regrouper par pays, ou calculer la croissance d’une année sur l’autre.
Melt avec des colonnes MultiIndex
Si votre DataFrame a des en-têtes de colonnes multi-niveaux, utilisez le paramètre col_level pour préciser quel niveau « melt » :
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)Pour des scénarios multi-niveaux complexes, vous devrez peut-être d’abord aplatir les colonnes avec droplevel() ou en joignant les niveaux avec un underscore avant de faire le melt.
Melt vs Pivot : opérations inverses
melt() et pivot() sont des opérations inverses. Melt convertit wide → long. Pivot convertit long → 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 92Différence clé : pivot() exige des combinaisons index-colonne uniques. Si vos données longues contiennent des doublons, utilisez plutôt pivot_table() avec une fonction d’agrégation.
Melt vs Stack vs wide_to_long
Pandas fournit plusieurs fonctions de remodelage. Voici quand utiliser chacune :
| Fonction | Direction | Idéal pour | Différence clé |
|---|---|---|---|
melt() | wide → long | Dé-pivoter des colonnes spécifiques en lignes | Basé sur les colonnes ; le plus intuitif pour débuter |
stack() | wide → long | Transformer des niveaux de colonnes en niveaux d’index | Basé sur l’index ; fonctionne avec MultiIndex |
wide_to_long() | wide → long | Colonnes avec préfixe commun et suffixe numérique (ex. score1, score2) | Analyse automatiquement les « stub names » |
pivot() | long → wide | Étaler des valeurs en colonnes (clés uniques) | Inverse de melt() |
unstack() | long → wide | Transformer des niveaux d’index en colonnes | Inverse de stack() |
Quand utiliser stack() à la place
stack() opère sur l’index des colonnes et le pousse dans l’index des lignes. C’est surtout utile si vous travaillez déjà avec un MultiIndex et que vous voulez remodeler au niveau de l’index :
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: int64Le résultat est une Series avec un MultiIndex, pas un DataFrame avec des colonnes nommées comme produit melt(). Utilisez melt() lorsque vous voulez un DataFrame propre avec des colonnes explicitement nommées.
Quand utiliser wide_to_long()
wide_to_long() est conçu pour des colonnes qui suivent un schéma de nommage comme score1, score2, score3 :
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 80Utilisez wide_to_long() lorsque vos colonnes ont un motif préfixe-suffixe cohérent. Sinon, melt() est plus flexible.
Considérations de performance
Pour la plupart des jeux de données (moins de quelques millions de lignes), melt() est suffisamment rapide. Voici des benchmarks sur un DataFrame de 100 000 lignes et 50 colonnes « melt » :
| Opération | Temps approximatif |
|---|---|
melt() avec 50 colonnes de valeurs | ~15 ms |
Équivalent stack() | ~10 ms |
Boucle manuelle avec concat() | ~500 ms |
Astuces pour de meilleures performances :
- Spécifiez
value_varsexplicitement — « melt » uniquement les colonnes nécessaires est plus rapide que tout « melt ». - Utilisez
ignore_index=True(valeur par défaut) — conserver l’index d’origine ajoute du surcoût. - Évitez de melt puis re-pivoter immédiatement — si vous avez besoin d’un autre format wide, envisagez
pivot_table()ourename()directement plutôt qu’un aller-retour. - Pour des DataFrames très volumineux (100M+ de lignes après melt), envisagez d’utiliser polars ou Dask, qui offrent l’évaluation lazy et le traitement parallèle.
# 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'
)Erreurs fréquentes et comment les corriger
1. KeyError : colonne introuvable
Cela arrive lorsqu’un nom de colonne dans id_vars ou value_vars n’existe pas dans le DataFrame :
# Wrong: column name has a typo
long = df.melt(id_vars=['stduent']) # KeyError
# Fix: check column names first
print(df.columns.tolist())2. Doublons inattendus
Melt ne crée pas lui-même des doublons — il crée une ligne par combinaison variables d’identification/valeur. Si vous voyez des doublons, cela signifie que vos données d’origine avaient des lignes d’identifiant dupliquées :
# Check for duplicates in your id columns
print(df.duplicated(subset=['student']).sum())3. Types de données mixtes dans la colonne de valeur
Lorsque vous « melt » des colonnes de types différents (par ex. int64 et float64), pandas convertit la colonne de valeurs vers le type le plus général. Si vous « melt » un mélange de colonnes numériques et de chaînes, la colonne de valeurs devient de type 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 objectPour éviter cela, « melt » les colonnes numériques et textuelles séparément.
Visualiser des données melt avec PyGWalker
Après avoir remodelé vos données du format wide vers le format long, l’étape suivante naturelle consiste à explorer le résultat visuellement — vérifier des distributions, comparer des groupes ou repérer des valeurs aberrantes. PyGWalker (opens in a new tab) est une bibliothèque Python open-source qui transforme n’importe quel pandas DataFrame en une interface d’exploration visuelle interactive de type Tableau, directement dans Jupyter Notebook.
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)Avec PyGWalker, vous pouvez glisser subject sur l’axe des x et score sur l’axe des y, puis colorer par student pour comparer instantanément les performances par matière — sans code de graphique. Il prend en charge les bar charts, scatter plots, box plots et plus encore, via du drag-and-drop.
Essayez PyGWalker dans Google Colab (opens in a new tab), Kaggle (opens in a new tab), ou installez-le avec
pip install pygwalker.
FAQ
Que fait pandas melt ?
Pandas melt() remodèle un DataFrame du format wide vers le format long. Il prend des colonnes et les transforme en lignes, en créant deux nouvelles colonnes : une pour les noms de colonnes d’origine (variable) et une pour les valeurs. On appelle aussi cela « unpivoting ».
Quelle est la différence entre melt et pivot dans pandas ?
melt() convertit le format wide en format long (les colonnes deviennent des lignes). pivot() fait l’inverse — il convertit le format long en format wide (les lignes deviennent des colonnes). Ce sont des opérations inverses. Si vous faites un melt sur un DataFrame puis un pivot du résultat avec les mêmes paramètres, vous retrouvez le DataFrame d’origine.
Quand utiliser melt plutôt que stack dans pandas ?
Utilisez melt() quand vous voulez un DataFrame propre avec des colonnes nommées et un contrôle explicite sur les colonnes à dé-pivoter. Utilisez stack() lorsque vous travaillez avec des colonnes MultiIndex et que vous voulez pousser des niveaux de colonnes dans l’index des lignes. melt() est plus intuitif pour débuter ; stack() est plus puissant pour des remodelages hiérarchiques.
Comment melt plusieurs colonnes dans pandas ?
Passez une liste de noms de colonnes au paramètre value_vars : df.melt(id_vars=['id'], value_vars=['col_a', 'col_b', 'col_c']). Toutes les colonnes listées seront dé-pivotées en lignes. Si vous omettez value_vars, pandas « melt » toutes les colonnes non listées dans id_vars.
Peut-on melt un DataFrame avec des noms de colonnes dupliqués ?
Pandas peut « melt » le DataFrame, mais le résultat peut être déroutant car la colonne variable contiendra des valeurs dupliquées. Renommez d’abord les colonnes dupliquées via df.columns = [...] ou df.rename() pour éviter toute ambiguïté.
Comment inverser une opération melt dans pandas ?
Utilisez pivot() ou pivot_table() pour reconvertir les données (long) en format wide : long.pivot(index='id', columns='variable', values='value'). Utilisez pivot_table() s’il existe des combinaisons index-colonne dupliquées nécessitant une agrégation.
Conclusion
La fonction pandas melt() est la méthode standard pour convertir des DataFrames au format wide en format long (tidy) en Python. Points clés :
- Utilisez
id_varspour préciser quelles colonnes conserver comme identifiants. - Utilisez
value_varspour contrôler quelles colonnes sont « melt ». Omettez-le pour tout « melt » sauf les identifiants. - Utilisez
var_nameetvalue_namepour donner des noms parlants aux colonnes de sortie. - Melt et pivot sont inverses — utilisez
melt()pour passer de wide à long etpivot()pour passer de long à wide. - Choisissez
melt()plutôt questack()lorsque vous voulez un DataFrame à plat avec des noms de colonnes explicites plutôt qu’une Series MultiIndex. - Nettoyez après le melt — utilisez des méthodes de chaîne sur la colonne variable pour retirer des préfixes/suffixes ou reformater les valeurs.
Après le remodelage, des outils comme PyGWalker (opens in a new tab) vous permettent d’explorer visuellement le résultat sans écrire de code de graphique, rendant le workflow d’analyse plus rapide et plus intuitif.