Pandas MultiIndex: Guía de indexación jerárquica
Updated on
MultiIndex desbloquea jerarquías ordenadas para datos de panel, series temporales y datos remodelados, pero muchas personas lo evitan porque el slicing parece frágil y el orden de los niveles puede resultar confuso.
- Problema: Las dimensiones anidadas (región + año, símbolo + campo) se vuelven desordenadas cuando se almacenan en columnas planas o en tablas anchas.
- Agitación: Los reshapes ad hoc generan nombres de columnas duplicados, ordenamientos rotos y errores al seleccionar por varias claves.
- Solución: Usar un pequeño conjunto de patrones repetibles: construir el MultiIndex con
set_index, segmentar de forma segura con.loc/.xs, reordenar conswaplevel/reorder_levels, y remodelar constack/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)
Referencia rápida
| Tarea | Método | Fragmento |
|---|---|---|
| Construir niveles desde columnas | set_index | df.set_index(["region", "year"]).sort_index() |
| Desde producto cartesiano | pd.MultiIndex.from_product | pd.MultiIndex.from_product([regions, years], names=["region", "year"]) |
| Hacer slice por nivel | .loc o .xs | df.loc[("EMEA", 2024)] o df.xs("EMEA", level="region") |
| Reordenar niveles | swaplevel, reorder_levels | df.swaplevel("region", "year") |
| Eliminar o aplanar | droplevel, reset_index | df.droplevel("year"), df.reset_index() |
| Remodelar wide/long | unstack / stack | df.unstack("field"), df.stack("field") |
Datos de ejemplo
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()
)Creación de estructuras MultiIndex
A partir de columnas existentes
sales = raw_df.set_index(["region", "year"]).sort_index()- Usa
sort_index()para obtener slicing predecible a través de los niveles. - Mantén como columnas normales aquellas que deban seguir siendo valores (por ejemplo, montos).
Desde producto o tuplas
idx = pd.MultiIndex.from_product(
[["EMEA", "NA"], [2023, 2024]],
names=["region", "year"],
)
frame = pd.DataFrame(index=idx, columns=["revenue"]).sort_index()from_product garantiza que exista cada combinación; usa from_tuples cuando ya tienes las parejas.
Selección con MultiIndex
# Una ruta única a través de la jerarquía
emea_2024 = df.loc[("EMEA", 2024)]
# Sección transversal por un nivel, conservando el resto
emea = df.xs("EMEA", level="region")
# Selección parcial con slices (requiere índice ordenado)
idx = pd.IndexSlice
subset = df.loc[idx[:, 2024, :], :].xs(cross-section) es cómodo cuando quieres conservar intactos los niveles restantes.- Para jerarquías de series temporales, ordena el índice y haz slicing con
IndexSlicepara mayor legibilidad.
Reordenar y limpiar niveles
# Traer year antes de region
reordered = df.swaplevel("region", "year").sort_index(level=["year", "region"])
# Reordenación explícita para 3+ niveles
df_reordered = df.reorder_levels(["metric", "region", "year"])
# Eliminar un nivel cuando ya no lo necesitas
flat = df.droplevel("metric")swapleveles rápido para intercambiar dos niveles adyacentes;reorder_levelsmaneja órdenes arbitrarios.- Después de reordenar, llama a
sort_index(level=...)para restaurar un orden monótono adecuado para slicing.
Remodelar con Stack y Unstack
Transforma tablas anchas en formato long ordenado (y viceversa) usando niveles del índice como pivotes.
wide = df.unstack("metric") # los valores de metric pasan a ser columnas
long_again = wide.stack("metric")- Usa
fill_value=enunstackpara reemplazar combinaciones faltantes. - Para operaciones tipo pivot sobre columnas, combina
set_index([...]).unstack()constack()en lugar de bucles manuales.
Cuándo usar MultiIndex vs. columnas
| Escenario | MultiIndex | Columnas simples |
|---|---|---|
| Las etiquetas jerárquicas dirigen el slicing (región → año → métrica) | ✅ Encaje natural para .loc/.xs | ⚠️ Requiere filtros/joins repetidos |
| Maquetación de reportes anchos | ✅ unstack para convertir niveles en columnas bajo demanda | ⚠️ Riesgo de nombres de columnas duplicados |
| Joins frecuentes sobre claves | ⚠️ Haz reset primero y luego merge | ✅ Mantén las claves como columnas para joins |
| Exportar a CSV/Parquet | ✅ reset_index() antes de escribir | ✅ Sin paso adicional |
Regla práctica: almacena datos con claves claras como columnas para intercambio; apóyate en MultiIndex cuando el slicing jerárquico o el reshaping sea el flujo de trabajo principal.
Errores comunes y cómo corregirlos
- Índice no ordenado bloquea el slicing: llama a
sort_index(level=[...])antes de hacer slices parciales. - Niveles sin nombre: establece
index.names(onames=enset_index) para que los slices y losresetsean claros. - Salida difícil de leer:
df.index.to_frame()expone los niveles como columnas para inspección, yreset_index()aplana cuando necesitas volver a columnas simples.
Estandarizando cómo construyes, segmentas, reordenas y remodelas objetos MultiIndex, obtienes jerarquías ordenadas sin la confusión habitual. Combina estos patrones con guías de reshaping como pandas-pivot-melt y utilidades para series temporales como pandas-resample para mantener datos multidimensionales manejables de punta a punta.