Skip to content

Pandas GroupBy: Agregación, Transform y Apply (Guía 2025)

Updated on

El patrón split-apply-combine es donde Pandas brilla. El reto: muchos dudan entre agg, transform o apply, o se topan con ordenaciones inesperadas, categorías perdidas o efectos de SettingWithCopy.

Marco PAS:

  • Problema: Los cálculos agrupados parecen opacos y lentos cuando solo se necesitan totales o ratios por fila.
  • Agitar: Usar apply de más o olvidar as_index=False genera formas inesperadas, columnas duplicadas y código lento.
  • Solución: Unas pocas recetas claras—agg para resúmenes, transform para métricas por fila, apply solo cuando haga falta—más opciones para ordenar y manejar grupos ausentes.

Guía rápida: cuándo usar cada método

MétodoForma resultanteMejor paraEjemplo
agg / aggregateUna fila por grupoResúmenes y varias métricasdf.groupby("team").agg(avg_score=("score","mean"))
transformMisma longitudFeatures por fila basadas en grupodf["z"] = df.groupby("team")["score"].transform("zscore")
applyFlexibleLógicas complejas si agg/transform no alcanzandf.groupby("team").apply(custom_fn)

Datos de ejemplo

import pandas as pd
 
data = {
    "team": ["A", "A", "B", "B", "B", "C"],
    "player": ["x1", "x2", "y1", "y2", "y3", "z1"],
    "score": [9, 7, 8, 6, 10, 3],
    "minutes": [30, 25, 28, 32, 20, 15],
}
df = pd.DataFrame(data)

Patrones de agregación (agg)

summary = (
    df.groupby("team", as_index=False)
      .agg(
          avg_score=("score", "mean"),
          max_score=("score", "max"),
          minutes_played=("minutes", "sum"),
      )
)
  • Usa named aggregation para mantener nombres limpios.
  • as_index=False conserva team como columna (útil para merges y gráficos).
  • sort=False mantiene el orden original si importa.

Multiagregación en una columna

df.groupby("team", as_index=False).agg(
    score_mean=("score", "mean"),
    score_std=("score", "std"),
    score_count=("score", "size"),
)

Features por fila (transform)

transform conserva la forma original y agrega métricas de grupo a cada fila.

df["score_pct_of_team"] = (
    df["score"] / df.groupby("team")["score"].transform("sum")
)

Z-score por equipo:

df["score_z"] = (
    df.groupby("team")["score"]
      .transform(lambda s: (s - s.mean()) / s.std(ddof=0))
)

Usa transform para:

  • Ratios frente a totales de grupo
  • Scores normalizados
  • Flags de grupo (ej. rank, cumcount)

Cuándo vale la pena apply

apply es flexible pero más lento; reservalo para lo que no cubran agg o transform.

def top_n(group, n=2):
    return group.nlargest(n, "score")
 
top_players = df.groupby("team").apply(top_n, n=1).reset_index(drop=True)

Prefiere agg/transform; usa apply cuando:

  • Debes devolver un número variable de filas por grupo.
  • La lógica requiere Python sin alternativa vectorizada.

Grupos faltantes y orden

result = (
    df.groupby("team", dropna=False, sort=False)
      .agg(avg_score=("score", "mean"))
)
  • dropna=False conserva etiquetas NaN.
  • sort=False evita reordenar—útil si el orden tiene significado.

GroupBy con varias llaves e índices

multi = (
    df.groupby(["team", "player"], as_index=False)
      .agg(score_mean=("score", "mean"))
)

Agrupando por niveles de índice:

df2 = df.set_index(["team", "player"])
df2.groupby(level="team")["score"].mean()

Errores comunes

ProblemaSolución
Formas inesperadas (Series vs DataFrame)Usa as_index=False o luego reset_index().
Nombres de columna duplicados tras mergeUsa named aggregation para definir los nombres.
Lentitud por applyCambia a agg/transform o métodos vectorizados.
Categorías ausentes en la salidaMantén observed=False (default) o asegura categorías; usa dropna=False para NaN.

Tips de exportación y gráficos

  • Tras agregar, ordena para presentar: summary.sort_values("avg_score", ascending=False).
  • Para gráficos, pivot del resumen: summary.pivot(index="team", values="avg_score").

Guías relacionadas


Puntos clave

  • Usa agg para resúmenes, transform para features por fila, apply con moderación.
  • Controla la forma con as_index y reset_index.
  • Gestiona orden y etiquetas faltantes con sort y dropna.
  • Prioriza métodos vectorizados para mantener rápida la canalización.