GroupBy & Agregación
El groupby de pandas implementa split-apply-combine: particiona las filas por claves, ejecuta una función por grupo y une los resultados en un resumen o un frame transformado.
Receta
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
import pandas as pd
summary = (
df.groupby("region", observed=True)["revenue"]
.agg(total="sum", avg="mean", n="count")
.reset_index()
)
pivot = pd.pivot_table(df, index="month", columns="region", values="revenue", aggfunc="sum")Cuándo usar esto:
- Resúmenes regionales o de productos en tablas de hechos (fact tables).
- Métricas de ventana (windowed metrics) que necesitan estadísticas por grupo.
- Pivoteo de datos largos a diseños de informes amplios (wide reporting layouts).
- Ingeniería de características (feature engineering) (medias a nivel de grupo para ML).
Ejemplo de Trabajo
import pandas as pd
sales = pd.DataFrame(
{
"region": pd.Categorical(["East", "West", "East", "West", "East"]),
"month": ["2025-01", "2025-01", "2025-02", "2025-02", "2025-02"],
"revenue": [120.0, 340.0, 150.0, 280.0, 130.0],
"units": [10, 25, 12, 20, 11],
}
)
# Agregación de métricas múltiples
by_region = (
sales.groupby("region", observed=True)
.agg(revenue_total=("revenue", "sum"), units_avg=("units", "mean"))
.reset_index()
)
# Porcentaje de la cuota regional por fila (transform mantiene el recuento de filas)
sales = sales.copy()
sales["share"] = sales.groupby("region", observed=True)["revenue"].transform(
lambda s: s / s.sum()
)
# Pivoteo para informes
pivot = pd.pivot_table(
sales,
index="month",
columns="region",
values="revenue",
aggfunc="sum",
fill_value=0,
observed=True,
)
print(by_region)
print(sales[["region", "revenue", "share"]])
print(pivot)Lo que esto demuestra:
- Agregación con nombre con
.agg(col=(field, func)) transformpara fracciones de grupo a nivel de fila.pivot_tableconfill_valuepara meses dispersos.observed=Trueen claves categóricas.
Inmersión Profunda
Cómo Funciona
- Split: hashea o ordena las filas por las claves de grupo.
- Apply: ejecuta una reducción (
sum,mean) o una transformación (rank,fillna). - Combine: apila los resultados en Series/DataFrame con un MultiIndex o columnas planas.
as_index=False(el valor predeterminado de pandas 2.x en muchas APIs) devuelve las claves como columnas.
agg vs transform vs apply
| Método | Filas de salida | Uso |
|---|---|---|
agg | Una por grupo | Resúmenes |
transform | Igual que la entrada | Estadísticas por grupo por fila |
apply | Varía | Lógica personalizada de Python (más lento) |
Notas de Python
import pandas as pd
# Claves múltiples
df.groupby(["region", "month"], observed=True)["revenue"].sum()
# Filtrar grupos por condición de agregación
df.groupby("region").filter(lambda g: g["revenue"].sum() > 500)Trampas Comunes
- Incluir NA en las claves de grupo -
dropna=Falsemantiene los grupos NaN; a menudo es accidental. Solución:dropna=True(predeterminado) o limpiar las claves primero. - Niveles categóricos no observados - aparecen regiones vacías sin
observed=True. Solución: pasarobserved=Trueen groupby/pivot de pandas 2.x. applydevolviendo formas inconsistentes - rompe el paso de combinación. Solución: preferiragg/transformintegrados; vectorizar la lógica personalizada.- Claves duplicadas en Pivot - las filas múltiples por (mes, región) necesitan
aggfunc. Solución: elegirsum,mean, ofirstexplícitamente. - Ordenar la salida de groupby - el índice desordenado dificulta la lectura de los informes. Solución:
.sort_values("revenue_total", ascending=False).
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Polars group_by | Agregaciones perezosas (lazy aggregations) más rápidas en datos grandes | Frames pequeños donde pandas ya está cargado |
| DuckDB SQL | Uniones (joins) y agregaciones complejas en una sola consulta | Resúmenes simples de una tabla |
pd.crosstab | Conteo de frecuencias de dos factores | Sumas de ingresos numéricos |
NumPy bincount | Sumas de cubos (buckets) enteros en datos 1-D | Múltiples columnas y manejo de NA |
Preguntas Frecuentes
¿Qué es observed=True?
- Limita el groupby categórico a las categorías presentes en los datos.
- Evita grupos vacíos de niveles de categoría no utilizados.
¿Cómo cuento valores distintos por grupo?
df.groupby("region")["customer_id"].nunique()¿Cómo obtengo el rango dentro de un grupo?
df["rank"] = df.groupby("region")["revenue"].rank(ascending=False)¿Puedo agregar múltiples columnas de manera diferente?
df.groupby("region").agg({"revenue": "sum", "units": "max"})¿Por qué es lento groupby?
applyde Python por grupo es el culpable habitual.- Usa
aggvectorizado, Polars o DuckDB para millones de filas.
¿Cómo reinicio el índice después de groupby?
out = df.groupby("region").sum().reset_index()¿Qué es la agregación con nombre?
.agg(total=("revenue", "sum"))nombra las columnas de salida directamente.- Más claro que las columnas MultiIndex de
.agg(["sum", "mean"]).
¿Cómo difieren pivot_table y groupby?
- Mismo motor subyacente - pivot es azúcar sintáctico para diseño ancho (wide layout).
- Usa pivot cuando los consumidores esperan columnas por categoría.
¿Cómo manejo grupos basados en tiempo?
df.groupby(pd.Grouper(key="date", freq="ME"))para cubos de fin de mes.- Asegúrate primero de que el tipo de dato sea datetime y la consistencia de zona horaria.
¿Puedo hacer groupby y graficar en una línea?
df.groupby("region")["revenue"].sum().plot(kind="bar")- Ordena los valores primero para gráficos legibles.
Relacionado
- Series y DataFrames de pandas - indexación
- Joins y Merges - enriquecer antes de agrupar
- Series Temporales -
Groupery remuestreo (resample) - Polars - group_by rápido a escala
Versiones de la Pila: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.