pandas pivot table & melt : remodeler large ↔︎ long

Donnez à vos données la forme qu’exige la question — une matrice de synthèse avec pivot_table, le format long rangé avec melt, et les remodelages de MultiIndex avec stack et unstack.

Remodelez un DataFrame pandas entre format large et format long : construisez une matrice de synthèse avec pivot_table (index, columns, values, aggfunc, margins), passez du large au long avec melt (id_vars, value_vars), étalez et repliez un MultiIndex avec stack et unstack, comptez des catégories avec crosstab, et comprenez pourquoi pivot_table est le choix sûr par défaut face à pivot.

Date de publication

17 juillet 2026

Modifié

18 juillet 2026

AstucePoints clés
  • pivot_table construit une matrice de synthèse — et agrège, donc elle ne bute jamais sur les doublons. pivot_table(index=, columns=, values=, aggfunc="mean") transforme des lignes en format long en une grille rows × columns d’un seul nombre récapitulatif par cellule ; margins=True ajoute les totaux de lignes et de colonnes.
  • pivot est pivot_table sans l’agrégation — et il lève une erreur sur les paires ligne/colonne en double. Ne l’employez que lorsque chaque cellule contient déjà exactement une valeur ; sinon pivot_table est le choix sûr par défaut.
  • melt passe du large au long — le format rangé (tidy) que réclament les tracés et le regroupement. df.melt(id_vars=, value_vars=) empile plusieurs colonnes en une seule paire variable/value ; c’est l’inverse de pivot, et c’est ce qui alimente seaborn et groupby.
  • stack/unstack remodèlent un MultiIndex. Après groupby([...]).mean(), unstack() étale le dernier niveau d’index en colonnes ; stack() le replie. C’est le passage large↔︎long rapide quand vos données portent déjà un MultiIndex.
  • crosstab compte des catégories. pd.crosstab(rows, cols) est un tableau de fréquences en un seul appel ; normalize= convertit les effectifs en proportions.

Introduction

Les mêmes données doivent prendre des formes différentes selon la tâche. Un tableau avec une ligne par manchot est parfait pour filtrer et fusionner, mais inadapté à un rapport — un lecteur veut une grille compacte espèce × sexe de masses moyennes, pas 344 lignes. Il est tout aussi inadapté pour tracer un diagramme en barres groupées — seaborn veut une unique colonne longue de valeurs, avec une colonne de regroupement à côté. Mêmes chiffres, trois formes différentes. Le remodelage permet de passer de l’une à l’autre, et sous pandas cela signifie pivot_table, melt, stack/unstack et crosstab.

Cette leçon est la boîte à outils du remodelage telle que vous vous en servez réellement : partez de lignes de manchots rangées (tidy), passez-les au pivot_table pour en faire une matrice de synthèse à glisser dans un rapport, ramenez un tableau large vers le long avec melt pour qu’un tracé puisse le regrouper, étalez et repliez un résultat de groupby avec unstack/stack, et comptez des catégories avec crosstab. Ici les tableaux imprimés sont les figures — chacun est petit et se lit à voix haute, de sorte que vous voyez exactement ce que chaque remodelage a fait à vos données.

Cette leçon s’appuie sur pandas DataFrames (chargement, groupby, agg — nous nous en servons sans les réexpliquer) et sur la leçon voisine Combiner : merge & join — on remodèle souvent un tableau juste après l’avoir fusionné. Les données des manchots sont fournies sous forme d’un petit CSV à côté de cette leçon (issu du jeu de données Palmer Station LTER / palmerpenguins), il n’y a donc rien à télécharger et aucun accès réseau au rendu. Chaque résultat ci-dessous a été produit par le code affiché, et les blocs se construisent dans l’ordre. Pour expérimenter, modifiez la cellule Essayez en direct à la fin et appuyez sur Run.

Le tableau rangé des manchots

Partez de la forme sous laquelle la plupart des données arrivent et restent : le format long (ou rangé, tidy) — une ligne par observation, une colonne par variable. Chaque ligne est un manchot ; les colonnes sont son espèce, son île, ses mesures et son sexe.

import pandas as pd

penguins = pd.read_csv("penguins.csv")

print("shape:", penguins.shape)
print(penguins[["species", "island", "sex", "body_mass_g"]].head())
shape: (344, 7)
  species     island     sex  body_mass_g
0  Adelie  Torgersen    Male       3750.0
1  Adelie  Torgersen  Female       3800.0
2  Adelie  Torgersen  Female       3250.0
3  Adelie  Torgersen     NaN          NaN
4  Adelie  Torgersen  Female       3450.0

344 lignes, 7 colonnes — une ligne par oiseau. Cette forme est idéale pour filtrer, regrouper et fusionner, mais elle ne répond pas d’un coup d’œil à « quelle est la masse corporelle moyenne de chaque espèce et sexe ? ». Pour cela, il faut disposer les chiffres dans une grille. C’est le premier remodelage.

pivot_table : la matrice de synthèse

pivot_table est le cheval de bataille. Vous nommez trois choses — ce qui descend dans l’index (les lignes), ce qui s’étale sur les columns, et quelles values résumer — plus aggfunc, la fonction qui réduit toutes les lignes concordantes à un seul nombre par cellule. Ici : l’espèce sur le côté, le sexe en haut, la masse corporelle moyenne dans chaque cellule.

matrix = pd.pivot_table(
    penguins,
    index="species",
    columns="sex",
    values="body_mass_g",
    aggfunc="mean",
).round(0)

print(matrix)
sex        Female    Male
species                  
Adelie     3369.0  4043.0
Chinstrap  3527.0  3939.0
Gentoo     4680.0  5485.0

Voilà un tableau de rapport. Chaque cellule est la masse corporelle moyenne des oiseaux de cette espèce et de ce sexe — les mâles Gentoo pèsent en moyenne 5485 g, les femelles Adelie 3369 g. pivot_table a pris les nombreuses lignes derrière chaque combinaison espèce/sexe et les a réduites à une seule moyenne, si bien que le résultat est une grille nette 3 × 2 quel que soit le nombre de lignes. C’est là tout l’intérêt d’aggfunc : pivot_table agrège toujours, ce qui explique précisément pourquoi c’est le choix sûr par défaut (voir plus bas).

Ajouter les totaux avec margins=True

Un rapport veut généralement aussi les totaux de lignes et de colonnes. margins=True ajoute une ligne et une colonne All — ici la moyenne globale par sexe, la moyenne globale par espèce, et la moyenne générale dans le coin :

with_totals = pd.pivot_table(
    penguins,
    index="species",
    columns="sex",
    values="body_mass_g",
    aggfunc="mean",
    margins=True,
).round(0)

print(with_totals)
sex        Female    Male     All
species                          
Adelie     3369.0  4043.0  3706.0
Chinstrap  3527.0  3939.0  3733.0
Gentoo     4680.0  5485.0  5092.0
All        3862.0  4546.0  4207.0

La colonne All donne la moyenne par espèce sur les deux sexes (Gentoo 5092 g), la ligne All la moyenne par sexe sur toutes les espèces (mâles 4546 g, femelles 3862 g), et le coin en bas à droite est la moyenne générale, 4207 g. Notez que les marges sont des moyennes des lignes sous-jacentes, pas des cellules — margins réagrège les données brutes, de sorte qu’un groupe déséquilibré ne peut pas fausser le total.

Résumer de plusieurs façons : une liste d’aggfunc

Passez une liste à aggfunc pour calculer plusieurs résumés d’un coup. Ici la masse moyenne et la taille du groupe, côte à côte :

mean_and_n = pd.pivot_table(
    penguins,
    index="species",
    columns="sex",
    values="body_mass_g",
    aggfunc=["mean", "count"],
).round(0)

print(mean_and_n)
             mean          count     
sex        Female    Male Female Male
species                              
Adelie     3369.0  4043.0     73   73
Chinstrap  3527.0  3939.0     34   34
Gentoo     4680.0  5485.0     58   61

Le résultat a maintenant des colonnes MultiIndex — un niveau supérieur (mean, count) au-dessus du niveau sex. Le bloc count confirme les tailles de groupe derrière chaque moyenne (73 Adelie de chaque sexe, 61 mâles Gentoo), ce qui permet de voir d’un coup d’œil quelles cellules reposent sur peu d’oiseaux. Atteignez un bloc précis avec un tuple : mean_and_n["count"]. (Les effectifs écartent les 11 manchots dont le sex est manquant, car pivot_table ignore les clés NaN par défaut.)

pivot vs pivot_table : pourquoi la version tableau est le choix par défaut

Il existe une fonction plus simple, pivot, qui remodèle du long vers le large sans agréger — elle se contente de placer chaque valeur dans sa cellule row × column. Cela ne fonctionne que si chaque cellule contient exactement une valeur. Nos données brutes comptent de nombreux manchots par espèce/sexe, donc pivot ne peut pas savoir quelle masse mettre dans la cellule Gentoo-mâle :

# pivot() refuses to guess — it raises when a cell would hold more than one value
try:
    penguins.pivot(index="species", columns="sex", values="body_mass_g")
except ValueError as e:
    print("ValueError:", e)
ValueError: Index contains duplicate entries, cannot reshape

Ce ValueError: Index contains duplicate entries, cannot reshape est l’erreur de remodelage la plus courante, et c’est toute la raison d’être de pivot_table : pivot_table = pivot + une étape d’agrégation, si bien qu’elle réduit les doublons au lieu d’échouer dessus. pivot n’est le bon outil que lorsque vos données sont déjà à une valeur par cellule — par exemple un tableau que vous venez de résumer. La grille des masses moyennes construite plus haut est exactement cela : une fois de retour au format long, pivot reconstruit proprement la grille large. Nous verrons cet aller-retour dans la section suivante.

Règle empirique : si vous remodelez des lignes brutes, utilisez pivot_table ; ne recourez à pivot que lorsque chaque cellule est garantie unique.

melt : du large au long (le format rangé)

melt est le mouvement inverse — il prend un tableau large et empile plusieurs colonnes en deux : l’une contenant les anciens noms de colonnes, l’autre les valeurs. C’est ainsi que l’on obtient des données longues/rangées, la forme que préfèrent groupby et toutes les bibliothèques de tracé. Prenez la matrice des masses moyennes, aplatissez-la de nouveau en un tableau simple, puis appliquez-lui melt :

wide = matrix.reset_index()          # species back to a column, sex names as columns
print("wide:\n", wide, "\n")

long = wide.melt(
    id_vars="species",               # keep this column as-is (the identifier)
    var_name="sex",                  # the melted column names go here
    value_name="mean_mass",          # their values go here
)
print("long:\n", long)
wide:
 sex    species  Female    Male
0       Adelie  3369.0  4043.0
1    Chinstrap  3527.0  3939.0
2       Gentoo  4680.0  5485.0 

long:
      species     sex  mean_mass
0     Adelie  Female     3369.0
1  Chinstrap  Female     3527.0
2     Gentoo  Female     4680.0
3     Adelie    Male     4043.0
4  Chinstrap    Male     3939.0
5     Gentoo    Male     5485.0

id_vars nomme la ou les colonnes à conserver comme identifiants ; toute autre colonne (Female, Male) est dépivotée en lignes. La grille 3 × 2 est devenue 6 lignes longues — une par combinaison espèce-et-sexe — les anciens en-têtes de colonnes vivant désormais dans une colonne sex et les chiffres dans mean_mass. Ce sont des données rangées : une observation par ligne, chaque variable dans sa propre colonne. Et comme chaque paire species/sex n’apparaît maintenant qu’une seule fois, pivot l’inverse parfaitement — long.pivot(index="species", columns="sex", values="mean_mass") renvoie la grille large d’origine. melt et pivot sont inverses l’un de l’autre.

La raison de s’en donner la peine : le format long est ce que veulent les outils de tracé.

import matplotlib.pyplot as plt
import seaborn as sns

sns.set_style("whitegrid")
palette = {"Female": "#3a86d4", "Male": "#f4a259"}

fig, ax = plt.subplots(figsize=(7, 4.5))
sns.barplot(data=long, x="species", y="mean_mass", hue="sex", palette=palette, ax=ax)

ax.set_xlabel("Species")
ax.set_ylabel("Mean body mass (g)")
ax.set_title("Mean penguin body mass by species and sex")
ax.legend(title="Sex", frameon=False)
sns.despine()
fig.tight_layout()
plt.show()
Grouped bar chart of mean penguin body mass in grams by species. Each species has two bars, Female and Male. Gentoo is far heavier than Adelie and Chinstrap at roughly 4680 and 5485 grams, and within every species the male bar is taller than the female bar. Female bars are azure, male bars orange, with a legend for sex.
Figure 1

Seaborn a lu la table longue directement : x="species" choisit les groupes, hue="sex" scinde chacun en deux barres — une ligne de la table longue par barre. La figure raconte clairement l’histoire que contenait la matrice : les Gentoo sont bien plus lourds que les Adelie et les Chinstrap, et au sein de chaque espèce les mâles pèsent plus que les femelles. Essayez de tracer cela à partir de la matrice large et vous devrez fournir les colonnes à la main au traceur ; à partir du format long, c’est un seul appel. C’est là le gain concret de melt — remodelez une fois, et le tracé en découle.

stack / unstack : remodeler un MultiIndex

Lorsque vos données portent déjà un MultiIndex — comme en produit un groupby sur plusieurs colonnes — stack et unstack sont le passage large↔︎long le plus rapide. Calculez la masse moyenne par espèce et par île et vous obtenez une Series longue à index sur deux niveaux :

grouped = penguins.groupby(["species", "island"])["body_mass_g"].mean().round(0)
print(grouped)
species    island   
Adelie     Biscoe       3710.0
           Dream        3688.0
           Torgersen    3706.0
Chinstrap  Dream        3733.0
Gentoo     Biscoe       5076.0
Name: body_mass_g, dtype: float64

C’est long : une valeur par espèce-et-île, indexée par les deux. unstack() étale le dernier niveau d’index (island) sur les colonnes, transformant la Series longue en une grille large :

wide_grid = grouped.unstack()
print(wide_grid)
island     Biscoe   Dream  Torgersen
species                             
Adelie     3710.0  3688.0     3706.0
Chinstrap     NaN  3733.0        NaN
Gentoo     5076.0     NaN        NaN

Maintenant les espèces descendent sur le côté et les îles s’alignent en haut — la même forme que donnerait pivot_table, mais directement à partir du groupby, sans redéfinir index/columns. Les cellules NaN sont honnêtes : les Chinstrap ne vivent que sur Dream, les Gentoo seulement sur Biscoe, donc ces combinaisons espèce/île n’ont tout simplement aucun oiseau. Pour revenir en arrière, stack() replie les colonnes en lignes et supprime les NaN :

print(wide_grid.stack())
species    island   
Adelie     Biscoe       3710.0
           Dream        3688.0
           Torgersen    3706.0
Chinstrap  Dream        3733.0
Gentoo     Biscoe       5076.0
dtype: float64

Vous voilà de retour à la Series longue (moins les combinaisons vides). Utilisez unstack/stack quand les données sont déjà indexées selon l’axe sur lequel vous voulez pivoter ; recourez à pivot_table quand vous partez de colonnes plates et voulez agréger dans la même étape.

crosstab : compter des catégories

Souvent la question est simplement « combien dans chaque combinaison ? » — un tableau de fréquences (ou de contingence). pd.crosstab le fait en un seul appel : passez les catégories de lignes et les catégories de colonnes, et il compte :

counts = pd.crosstab(penguins["species"], penguins["island"])
print(counts)
island     Biscoe  Dream  Torgersen
species                            
Adelie         44     56         52
Chinstrap       0     68          0
Gentoo        124      0          0

Chaque cellule est le nombre d’oiseaux de cette espèce sur cette île — les Gentoo sont 124 sur Biscoe et nulle part ailleurs, les Chinstrap 68 sur Dream uniquement, les Adelie répartis sur les trois (44 / 56 / 52). C’est le plan d’échantillonnage de l’étude, lu directement sur les données. crosstab est en réalité un pivot_table avec aggfunc="count" et une signature plus commode pour le cas courant du comptage.

Pour convertir les effectifs en proportions, passez normalize=. normalize="index" fait que chaque ligne somme à 1 — ici, la part de chaque espèce présente sur chaque île :

props = pd.crosstab(
    penguins["species"], penguins["island"], normalize="index"
).round(2)
print(props)
island     Biscoe  Dream  Torgersen
species                            
Adelie       0.29   0.37       0.34
Chinstrap    0.00   1.00       0.00
Gentoo       1.00   0.00       0.00

Maintenant la lecture est au sein de chaque espèce : 100 % des Gentoo sont sur Biscoe, 100 % des Chinstrap sur Dream, tandis que les Adelie se répartissent à peu près également (29 % / 37 % / 34 %). Utilisez normalize="columns" pour les parts au sein de chaque île, ou normalize=True pour la part de chaque cellule dans le total général. Un effectif brut répond à « combien » ; un crosstab normalisé répond à « quelle fraction ».

Quel remodelage pour quelle question ?

Choisissez l’outil en fonction de ce que vous cherchez à produire, pas par habitude :

Votre objectif L’outil L’appel
Une grille de synthèse (lignes × cols) à partir de données brutes, en agrégeant pivot_table pd.pivot_table(df, index=, columns=, values=, aggfunc=)
Totaux de lignes/colonnes sur cette grille margins=True pd.pivot_table(..., margins=True)
Long → large quand chaque cellule est déjà unique pivot df.pivot(index=, columns=, values=)
Large → long (rangé) pour tracer/regrouper melt df.melt(id_vars=, value_vars=)
Étaler un niveau de MultiIndex en colonnes unstack series.unstack()
Replier des colonnes dans un niveau de MultiIndex stack df.stack()
Effectifs/proportions de combinaisons de catégories crosstab pd.crosstab(rows, cols, normalize=)

En cas de doute : agréger des lignes brutes en une grille → pivot_table ; aplatir un tableau large pour un tracé → melt ; compter des catégories → crosstab. Et rappelez-vous que pivot échoue sur les doublons tandis que pivot_table les agrège — c’est cette différence qui fait trébucher la plupart des gens.

La même idée en R

Vous travaillez en R, ou dans les deux langages ? Les équivalents se trouvent dans la leçon Remodeler des données en R (tidyr) : le melt de pandas correspond au pivot_longer() de tidyr (large → long), et pivot_table/pivot à pivot_wider() (long → large). L’idée des données rangées — une observation par ligne — est la même dans les deux, et c’est pourquoi le format long est la forme que récompensent la plupart des outils.

Essayez en direct

Les blocs ci-dessus ont été exécutés au moment du rendu. Modifiez celui-ci et appuyez sur Run pour remodeler les manchots vous-même — il s’exécute dans votre navigateur via Pyodide (sans installation). Le premier Run télécharge pandas une fois (~20 Mo), après quoi il est mis en cache et instantané.

🟢 Avec un agent IA

Une table dans la mauvaise forme ? Collez un df.head() et dites à Prova la forme qu’il vous faut — « transforme cette table longue en une matrice espèce-par-année des ventes moyennes » ou « melt ces quatre colonnes de mesures en une seule pour tracer. » Elle choisit entre pivot_table, melt et crosstab selon votre objectif, écrit l’appel exact index=/columns=/id_vars=, et vous prévient quand pivot lèverait une erreur sur des doublons. Parce que le runtime est juste là, vous l’exécutez et lisez vous-même la table remodelée au lieu de faire confiance à un appel qui semble correct mais a silencieusement agrégé la mauvaise colonne. The runtime is the judge. Demander à Prova →

Problèmes fréquents

ValueError: Index contains duplicate entries, cannot reshape. Vous avez appelé pivot (et non pivot_table) sur des données comptant plus d’une ligne par paire index/columns, si bien que pandas ne peut pas décider quelle valeur va dans la cellule. Passez à pivot_table et fournissez un aggfunc ("mean", "sum", "count", …) pour réduire les doublons — ou, si chaque cellule doit vraiment être unique, repérez les coupables avec df.duplicated(subset=["index_col", "columns_col"]) et corrigez d’abord les données.

pivot_table n’a rien renvoyé (ou que des NaN). Presque toujours, la colonne values n’est pas numérique et l’aggfunc="mean" par défaut n’avait rien à moyenner — vérifiez le dtype de la colonne, et utilisez aggfunc="count"/"first" pour une colonne non numérique. Les lignes dont la clé index/columns est NaN sont écartées par défaut ; passez dropna=False pour les conserver.

Les colonnes MultiIndex sont malcommodes à sélectionner après un pivot multi-aggfunc. Passer une liste à aggfunc (ou plusieurs values) vous donne deux niveaux d’en-têtes de colonnes. Atteignez un bloc avec un tuple — result["mean"] ou result[("mean", "Male")] — ou aplatissez les en-têtes avec result.columns = ["_".join(c) for c in result.columns] si un tableau à un seul niveau est plus commode à manipuler ensuite.

melt a absorbé une colonne que vous vouliez conserver. Toute colonne non listée dans id_vars est dépivotée dans la colonne value. Si un identifiant a disparu dans le melt, ajoutez-le à id_vars ; pour ne remodeler que certaines colonnes et laisser le reste intact, nommez-les explicitement dans value_vars.

Questions fréquentes

pivot remodèle du long vers le large sans agréger — il faut que chaque paire index/columns corresponde à exactement une valeur, et il lève une ValueError en cas de doublons. pivot_table ajoute une étape d’agrégation (aggfunc, "mean" par défaut), si bien qu’il réduit plusieurs lignes par cellule à un seul nombre récapitulatif et n’échoue jamais sur les doublons. N’utilisez pivot que lorsque vos données sont déjà à une valeur par cellule ; recourez à pivot_table pour des données brutes — c’est le choix sûr par défaut.

Utilisez df.melt() : nommez les colonnes à conserver comme identifiants avec id_vars=, et pandas empile toutes les autres colonnes en une paire variable/value (renommez-les avec var_name=/value_name=). Pour ne remodeler que certaines colonnes, listez-les dans value_vars=. Le format long — une observation par ligne — est la forme qu’attendent groupby et les bibliothèques de tracé comme seaborn.

Si chaque cellule index/columns est déjà unique, utilisez df.pivot(index=, columns=, values=). Si plusieurs lignes partagent une cellule et que vous voulez les résumer, utilisez plutôt pd.pivot_table(df, index=, columns=, values=, aggfunc=) — il agrège les doublons. Lorsque les données portent déjà un MultiIndex (par exemple après groupby([...]).mean()), .unstack() étale le dernier niveau d’index en colonnes en un seul appel.

Ce sont des inverses qui remodèlent un MultiIndex. unstack() fait pivoter un niveau d’index vers le haut dans les colonnes (long → large) ; stack() pousse un niveau de colonnes vers le bas dans l’index (large → long). Après df.groupby(["a", "b"]).mean(), .unstack() étale le niveau b en haut, et .stack() le replie — en supprimant les cellules NaN sans données.

Utilisez pd.crosstab(rows, cols) — passez les catégories de lignes et de colonnes et il compte chaque combinaison en un seul appel. Ajoutez normalize="index" (chaque ligne somme à 1), "columns", ou True (part du total général) pour obtenir des proportions plutôt que des effectifs bruts. C’est un pivot_table avec aggfunc="count" et une signature plus simple pour le cas du comptage.

Testez vos connaissances

Utilisez la table des manchots de la cellule Essayez en direct ci-dessus (penguins = pd.read_csv("penguins.csv")).

Tâche 1. Construisez un pivot_table de la longueur moyenne des nageoires (flipper_length_mm) avec les espèces dans les lignes et les îles dans les colonnes. Quelles cellules espèce/île sont vides, et pourquoi ?

pd.pivot_table(penguins, index="species", columns="island", values="flipper_length_mm", aggfunc="mean"). Les cellules vides sont les combinaisons espèce/île sans aucun oiseau.

grid = pd.pivot_table(
    penguins, index="species", columns="island",
    values="flipper_length_mm", aggfunc="mean",
).round(1)
print(grid)

Les Chinstrap (Dream uniquement) et les Gentoo (Biscoe uniquement) laissent des NaN dans les îles où ils n’ont jamais été échantillonnés — seuls les Adelie apparaissent sur les trois. Les NaN ne sont pas des données manquantes ; ce sont des combinaisons qui n’existent pas.

Tâche 2. Réalisez un crosstab de espèce × sexe en proportions au sein de chaque espèce (normalize="index"). Quel partage attendez-vous en gros, et les données le montrent-elles ?

print(pd.crosstab(penguins["species"], penguins["sex"], normalize="index").round(2))

Chaque espèce est proche d’un partage 50/50 mâle/femelle — l’étude a échantillonné les sexes de façon à peu près égale au sein de chaque espèce, donc chaque ligne est proche de 0.50 / 0.50.

Vérification rapide. Vous appelez penguins.pivot(index="species", columns="sex", values="body_mass_g") sur la table brute et obtenez une ValueError au sujet d’entrées en double. Quel est le correctif ?

Il y a de nombreux manchots par espèce/sexe, donc pivot ne peut pas mettre une seule valeur dans chaque cellule. Utilisez pivot_table avec un aggfunc (par exemple aggfunc="mean") — il agrège les lignes en double en un seul nombre par cellule au lieu de lever une erreur. pivot ne fonctionne que lorsque chaque paire index/columns est déjà unique.

Conclusion

Vous savez désormais donner à un DataFrame la forme qu’exige la tâche : pivot_table pour une matrice de synthèse (avec margins pour les totaux et une liste d’aggfunc pour plusieurs résumés à la fois), melt pour le format long rangé que veulent le tracé et le regroupement, stack/unstack pour le remodelage rapide d’un MultiIndex, et crosstab pour les effectifs et les proportions. Tout aussi important, vous connaissez le piège — pivot lève une erreur sur les cellules en double tandis que pivot_table les agrège — donc vous choisissez par défaut l’outil qui agrège pour des données brutes. Remodelez tôt, vérifiez que le tableau imprimé a bien la forme voulue, et le reste de l’analyse devient plus facile.

Leçons connexes

Cette page vous a-t-elle été utile ?

Prouvez que vous savez le faire. Maîtrisez toute la série Manipulation de données en Python — suivez votre parcours, construisez des projets et obtenez un certificat.

Commencer gratuitement →

Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.

dès 15 $/mois facturé annuellement

Passer à Pro →

✓ Vous êtes Pro — continuez. The runtime is the judge.

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {pandas pivot table \& melt : remodeler large ↔ long},
  date = {2026-07-17},
  url = {https://www.datanovia.com/learn/programming/python-data-wrangling/reshape-pivot-melt},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“pandas pivot table & melt : remodeler large ↔︎ long.” 2026. July 17. https://www.datanovia.com/learn/programming/python-data-wrangling/reshape-pivot-melt.