Pandas MultiIndex : guide de l’indexation hiérarchique
Updated on
MultiIndex débloque des hiérarchies propres pour les données de panel, de séries temporelles et les données remodelées, mais beaucoup d’utilisateurs l’évitent car le découpage semble fragile et l’ordre des niveaux peut devenir déroutant.
- Problème : Les dimensions imbriquées (region + year, symbol + field) deviennent difficiles à gérer lorsqu’elles sont stockées dans de simples colonnes ou dans des tableaux larges.
- Agitation : Les remodelages ad hoc entraînent des noms de colonnes dupliqués, des tris cassés et des erreurs lors des sélections sur plusieurs clés.
- Solution : Utiliser un petit ensemble de schémas répétables : construire un MultiIndex avec
set_index, découper en toute sécurité avec.loc/.xs, réordonner avecswaplevel/reorder_levels, et remodeler avecstack/unstack.
Want an AI agent that understands your pandas notebooks and MultiIndex slicing?
RunCell is a JupyterLab AI agent that can read your code, analyze DataFrames, understand notebook context, debug errors, and even generate & execute code for you. It works directly inside JupyterLab—no switching windows or copy-pasting.
👉 Try RunCell: runcell.dev (opens in a new tab)
Référence rapide
| Tâche | Méthode | Extrait |
|---|---|---|
| Construire des niveaux à partir de colonnes | set_index | df.set_index(["region", "year"]).sort_index() |
| À partir d’un produit cartésien | pd.MultiIndex.from_product | pd.MultiIndex.from_product([regions, years], names=["region", "year"]) |
| Découper par niveau | .loc ou .xs | df.loc[("EMEA", 2024)] ou df.xs("EMEA", level="region") |
| Réordonner les niveaux | swaplevel, reorder_levels | df.swaplevel("region", "year") |
| Supprimer ou aplatir | droplevel, reset_index | df.droplevel("year"), df.reset_index() |
| Remodeler wide/long | unstack / stack | df.unstack("field"), df.stack("field") |
Données d’exemple
import pandas as pd
records = [
("EMEA", 2023, "revenue", 120),
("EMEA", 2023, "profit", 25),
("EMEA", 2024, "revenue", 140),
("NA", 2024, "revenue", 210),
("NA", 2024, "profit", 50),
]
df = (
pd.DataFrame(records, columns=["region", "year", "metric", "value"])
.set_index(["region", "year", "metric"])
.sort_index()
)Créer des structures MultiIndex
À partir de colonnes existantes
sales = raw_df.set_index(["region", "year"]).sort_index()- Utiliser
sort_index()pour un découpage prévisible à travers les niveaux. - Garder en dehors de l’index les colonnes qui doivent rester « normales » (par exemple les montants).
À partir d’un produit ou de tuples
idx = pd.MultiIndex.from_product(
[["EMEA", "NA"], [2023, 2024]],
names=["region", "year"],
)
frame = pd.DataFrame(index=idx, columns=["revenue"]).sort_index()from_product garantit que chaque combinaison existe ; utiliser from_tuples lorsque vous avez déjà les paires.
Sélectionner avec un MultiIndex
# Chemin unique dans la hiérarchie
emea_2024 = df.loc[("EMEA", 2024)]
# Coupe transversale sur un niveau, en conservant les autres
emea = df.xs("EMEA", level="region")
# Sélection partielle avec slices (nécessite un index trié)
idx = pd.IndexSlice
subset = df.loc[idx[:, 2024, :], :].xs(cross-section) est pratique lorsque vous voulez conserver les niveaux restants intacts.- Pour les hiérarchies de séries temporelles, trier l’index puis découper avec
IndexSlicepour plus de lisibilité.
Réordonner et nettoyer les niveaux
# Mettre year avant region
reordered = df.swaplevel("region", "year").sort_index(level=["year", "region"])
# Réordonnancement explicite pour 3+ niveaux
df_reordered = df.reorder_levels(["metric", "region", "year"])
# Supprimer un niveau quand vous n’en avez plus besoin
flat = df.droplevel("metric")swaplevelest rapide pour échanger deux niveaux adjacents ;reorder_levelsgère les ordres arbitraires.- Après réordonnancement, appeler
sort_index(level=...)pour restaurer un ordre monotone pour le découpage.
Remodeler avec Stack et Unstack
Transformer des tableaux larges (wide) en forme longue (tidy long) (et inversement) en utilisant les niveaux d’index comme pivots.
wide = df.unstack("metric") # metric values become columns
long_again = wide.stack("metric")- Utiliser
fill_value=dansunstackpour remplacer les combinaisons manquantes. - Pour des opérations de type pivot sur les colonnes, combiner
set_index([...]).unstack()avecstack()plutôt que des boucles manuelles.
Quand utiliser MultiIndex vs. des colonnes simples
| Scénario | MultiIndex | Colonnes simples |
|---|---|---|
| Des étiquettes hiérarchiques pilotent le découpage (region → year → metric) | ✅ Naturel avec .loc/.xs | ⚠️ Nécessite des filtres/join répétés |
| Mise en page de reporting wide | ✅ unstack vers des colonnes à la demande | ⚠️ Risque de noms de colonnes dupliqués |
| Fusions fréquentes sur des clés | ⚠️ Faire reset d’abord, puis merge | ✅ Garder les clés comme colonnes pour les joins |
| Export en CSV/Parquet | ✅ reset_index() avant l’écriture | ✅ Pas d’étape supplémentaire |
Règle pratique : stocker les données avec des clés claires sous forme de colonnes pour l’échange ; utiliser MultiIndex lorsque le découpage hiérarchique ou le remodelage est le flux de travail principal.
Pièges courants et solutions
- Index non trié qui bloque le découpage : appeler
sort_index(level=[...])avant les sélections partielles. - Niveaux sans nom : définir
index.names(ounames=dansset_index) pour garder des sélections et desresetexplicites. - Sortie difficile à lire :
df.index.to_frame()expose les niveaux en tant que colonnes pour inspection, etreset_index()aplatit la structure lorsque vous avez besoin de colonnes simples.
En standardisant la façon dont vous construisez, découpez, réordonnez et remodeler les objets MultiIndex, vous obtenez des hiérarchies propres sans la confusion habituelle. Associez ces schémas à des guides de remodelage comme pandas-pivot-melt et à des aides pour séries temporelles telles que pandas-resample pour garder des données multidimensionnelles gérables de bout en bout.