Volver a la lista

groupby: patrón de dividir-aplicar-combinar

Comprende el funcionamiento de `groupby` en pandas mediante el enfoque Split-Apply-Combine y aprende patrones prácticos de agregación.

Intermedio
|
10min
|
Verificado (2026-07)
groupbysplit-apply-combineagregaciónoperaciones por grupopandas
Progreso0/17 (0%)

groupby — Patrón de Dividir-Aplicar-Combinar

Al finalizar este tema

Podrás explicar el funcionamiento interno de pandas groupby() mediante el patrón de Dividir-Aplicar-Combinar y adquirirás familiaridad con los patrones de agregación, transformación y filtrado por grupo que se utilizan con frecuencia en la práctica.


¿Por qué son necesarias las operaciones por grupo?

El "promedio general" es df["score"].mean() en una sola línea. Sin embargo, las preguntas prácticas suelen tener esta forma:

  • ¿Cuál es el salario promedio por departamento?
  • ¿Cuál es la suma de ventas mensuales?
  • ¿Cuál es el producto más vendido por categoría?

En el momento en que aparece "~por", se requieren operaciones por grupo. Esta es la función de groupby().


Patrón de Dividir-Aplicar-Combinar

Este patrón, nombrado por Hadley Wickham en 2011, es la estructura de pensamiento más recurrente en el análisis de datos.

text
Datos originales
┌────────┬──────┬───────┐
│ dept   │ name │ score │
├────────┼──────┼───────┤
│ Sales  │ Alice│   85  │
│ Sales  │ Bob  │   90  │
│ Dev    │ Carol│   95  │
│ Dev    │ Dave │   88  │
│ HR     │ Eve  │   78  │
└────────┴──────┴───────┘

1. SPLIT — dividir por departamento
   Sales: [85, 90]
   Dev:   [95, 88]
   HR:    [78]

2. APPLY — aplicar una función a cada grupo (por ejemplo, la media)
   Sales: 87.5
   Dev:   91.5
   HR:    78.0

3. COMBINE — reunir los resultados en uno
   ┌────────┬───────┐
   │ dept   │ score │
   ├────────┼───────┤
   │ Dev    │  91.5 │
   │ HR     │  78.0 │
   │ Sales  │  87.5 │
   └────────┴───────┘

En pandas, estos tres pasos se realizan en una sola línea:

python
df.groupby("dept")["score"].mean()

Uso básico

python
import pandas as pd
df = pd.DataFrame({
"dept": ["Sales", "Sales", "Dev", "Dev", "HR"],
"name": ["Alice", "Bob", "Carol", "Dave", "Eve"],
"score": [85, 90, 95, 88, 78],
"salary": [50000, 52000, 70000, 68000, 45000]
})
# Puntuación media por departamento
df.groupby("dept")["score"].mean()
# dept
# Dev 91.5
# HR 78.0
# Sales 87.5
# Suma de salarios por departamento
df.groupby("dept")["salary"].sum()
# dept
# Dev 138000
# HR 45000
# Sales 102000

¿Qué es un objeto GroupBy?

python
grouped = df.groupby("dept")
print(type(grouped)) # <class 'pandas.core.groupby.DataFrameGroupBy'>

groupby() no se calcula de inmediato. La evaluación diferida (lazy evaluation) significa que el cálculo solo se ejecuta cuando se aplica alguna función (como mean, sum, etc.). Esto evita cálculos innecesarios en conjuntos de datos grandes.

Verificación del contenido del grupo

python
for name, group in df.groupby("dept"):
print(f"\n--- {name} ---")
print(group)
# --- Dev ---
# dept name score salary
# 2 Dev Carol 95 70000
# 3 Dev Dave 88 68000
# --- HR ---
# ...

Varias funciones de agregación

Una columna, múltiples funciones

python
df.groupby("dept")["score"].agg(["mean", "min", "max", "count"])
# mean min max count
# dept
# Dev 91.5 88 95 2
# HR 78.0 78 78 1
# Sales 87.5 85 90 2

Funciones diferentes por columna

python
df.groupby("dept").agg(
avg_score=("score", "mean"),
total_salary=("salary", "sum"),
headcount=("name", "count")
)
# avg_score total_salary headcount
# dept
# Dev 91.5 138000 2
# HR 78.0 45000 1
# Sales 87.5 102000 2

La agregación con nombre (nombre_columna=("columna_original", "función")) es la forma más limpia, ya que permite especificar los nombres de las columnas del resultado de una sola vez.


Agrupación por varias columnas

python
sales = pd.DataFrame({
"region": ["East", "East", "West", "West", "East", "West"],
"category": ["A", "B", "A", "B", "A", "A"],
"revenue": [100, 200, 150, 250, 120, 180]
})
sales.groupby(["region", "category"])["revenue"].sum()
# region category
# East A 220
# B 200
# West A 330
# B 250

Al pasar varias columnas como lista, se genera un índice jerárquico (MultiIndex).

python
# Convertir MultiIndex en columnas normales
result = sales.groupby(["region", "category"])["revenue"].sum().reset_index()
# region category revenue
# 0 East A 220
# 1 East B 200
# 2 West A 330
# 3 West B 250

reset_index() convierte la clave de grupo desde el índice de nuevo a una columna normal. Esta forma es conveniente para tareas posteriores (visualización, guardado, etc.).


transform — transformación por grupo

agg() devuelve un único valor por grupo (5 filas → 3 filas). transform() devuelve un resultado del mismo tamaño que el original (5 filas → 5 filas).

python
# Añadir al conjunto original la media de cada departamento
df["dept_avg"] = df.groupby("dept")["score"].transform("mean")
print(df)
# dept name score salary dept_avg
# 0 Sales Alice 85 50000 87.5
# 1 Sales Bob 90 52000 87.5
# 2 Dev Carol 95 70000 91.5
# 3 Dev Dave 88 68000 91.5
# 4 HR Eve 78 45000 78.0

A cada fila se le adjunta el promedio de su propio departamento. Con esto, se puede calcular la puntuación en comparación con el promedio del departamento:

python
df["vs_avg"] = df["score"] - df["dept_avg"]
# Alice: 85 - 87.5 = -2.5 (por debajo de la media del departamento)
# Carol: 95 - 91.5 = +3.5 (por encima de la media del departamento)

filter — Filtrado por grupo

Mantiene o elimina todo el grupo que cumple con la condición.

python
# Solo departamentos con al menos dos personas
df.groupby("dept").filter(lambda g: len(g) >= 2)
# dept name score salary
# 0 Sales Alice 85 50000
# 1 Sales Bob 90 52000
# 2 Dev Carol 95 70000
# 3 Dev Dave 88 68000

El grupo completo de HR (1 persona) ha sido eliminado. El núcleo de filter() es filtrar por grupos, no por filas individuales.


Patrón práctico: Análisis de ventas mensuales

python
orders = pd.DataFrame({
"date": pd.to_datetime([
"2026-01-05", "2026-01-15", "2026-02-03",
"2026-02-20", "2026-03-10", "2026-03-25"
]),
"product": ["Widget", "Gadget", "Widget", "Gadget", "Widget", "Widget"],
"amount": [1200, 800, 1500, 900, 1100, 1300]
})
# Ventas totales por mes
monthly = orders.groupby(orders["date"].dt.to_period("M"))["amount"].sum()
print(monthly)
# date
# 2026-01 2000
# 2026-02 2400
# 2026-03 2400
# Ventas mensuales medias por producto
orders.groupby("product").agg(
total=("amount", "sum"),
avg=("amount", "mean"),
count=("amount", "count")
)
# total avg count
# Gadget 1700 850.0 2
# Widget 5100 1275.0 4

En los datos de fecha, crear grupos mensuales con .dt.to_period("M") es un patrón muy común.


Resumen clave

MétodoAcciónTamaño del resultado
agg()Agregación por grupo (suma, media, recuento...)Número de grupos (disminuye)
transform()Transformación por grupo (mantiene el tamaño original)Igual que el original
filter()Mantiene todos los grupos que cumplen la condiciónIgual o menor que el original

groupby() es la función más potente y utilizada en pandas. Si puede visualizar el patrón Split-Apply-Combine, puede descomponer de forma natural incluso las agregaciones complejas en tres pasos: "dividir por qué columna (Split), aplicar qué función (Apply) y combinar los resultados en qué formato (Combine)".


💬 Preguntas y comentarios

0 comentarios

Puedes publicar sin iniciar sesión. Los comentarios de invitados no pueden editarse ni eliminarse después.

0/2000

Cargando...