0Pricing
Pandas & NumPy Academy · Lección

apply() con GroupBy

Pase una función que opere sobre varias filas a groupby().apply() para calcular resúmenes complejos a nivel de grupo que agg() no puede expresar.

apply() con GroupBy es una lección gratuita de Pandas & NumPy Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Pandas & NumPy Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Pandas & NumPy Academy incluye 4 lecciones en total.

Por qué GroupBy necesita apply()

El método integrado agg() permite realizar agregaciones sencillas, como sumas, medias y recuentos, con una salida escalar por grupo. Sin embargo, algunos cálculos a nivel de grupo requieren examinar el sub-DataFrame completo del grupo, no solo una columna. groupby().apply(func) pasa el DataFrame completo del grupo a su función y recopila los resultados, lo que permite crear resúmenes complejos que agg() no puede expresar.

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'region': ['North', 'North', 'South', 'South', 'North'],
    'product': ['A', 'B', 'A', 'A', 'C'],
    'revenue': [100, 250, 180, 90, 300]
})
print(df)

Devolver un escalar por grupo

Cuando la función que se pasa a groupby().apply() devuelve un escalar, el resultado es una Series indexada por las claves de grupo, idéntica a la que produce agg(). Esta forma resulta útil cuando el escalar requiere lógica basada en varias columnas, como calcular la proporción entre los ingresos del producto principal y los ingresos totales del grupo, algo que no se puede expresar en una única especificación de columna de agg().

def top_product_share(group):
    top = group['revenue'].max()
    total = group['revenue'].sum()
    return top / total

share = df.groupby('region').apply(top_product_share)
print(share)

Devolver una Series por grupo

Cuando la función devuelve una pd.Series, el resultado tiene un MultiIndex: el nivel externo es la clave de grupo y el nivel interno es el índice de la Series. Esto resulta útil para calcular varias estadísticas por grupo en una sola llamada a apply y producir una tabla de resumen en la que cada grupo tiene varias filas de métricas.

def group_stats(group):
    return pd.Series({
        'total': group['revenue'].sum(),
        'top_product': group.loc[group['revenue'].idxmax(), 'product'],
        'n_products': group['product'].nunique()
    })

result = df.groupby('region').apply(group_stats)
print(result)

Devolver un DataFrame por grupo

Cuando la función devuelve un pd.DataFrame, groupby().apply() concatena verticalmente todos los sub-DataFrames. Esta es la forma más potente: permite filtrar o transformar las filas de cada grupo y devolver un subconjunto modificado. Por ejemplo, puede conservar solo los 2 productos con mayores ingresos de cada región.

def top2_per_region(group):
    return group.nlargest(2, 'revenue')

top2 = df.groupby('region').apply(top2_per_region)
print(top2.reset_index(drop=True))

Calcular puntuaciones Z dentro de cada grupo

Un uso habitual de groupby().apply() es calcular la estandarización dentro de cada grupo. En lugar de normalizar los ingresos con respecto a todos los pedidos, lo que mezcla las regiones, puede calcular la puntuación Z de los ingresos dentro de cada región. Una puntuación Z de 2 en North significa «2 desviaciones estándar por encima de la media de North», un punto de referencia más significativo que estar 2 desviaciones estándar por encima de la media global.

def within_group_zscore(group):
    mean = group['revenue'].mean()
    std = group['revenue'].std()
    group = group.copy()
    group['revenue_z'] = (group['revenue'] - mean) / std
    return group

df_z = df.groupby('region').apply(within_group_zscore).reset_index(drop=True)
print(df_z)

Agregación personalizada: media winsorizada

La media winsorizada recorta los valores extremos antes de calcular la media, por lo que es más robusta que la media simple en distribuciones sesgadas. Esta agregación personalizada no se puede expresar con las funciones estándar de agg(), pero es sencilla con groupby().apply(): recorte los valores en los percentiles 5 y 95 dentro de cada grupo y, después, calcule la media de los valores recortados.

def winsorised_mean(group, lower_pct=0.05, upper_pct=0.95):
    col = group['revenue']
    lo = col.quantile(lower_pct)
    hi = col.quantile(upper_pct)
    clipped = col.clip(lo, hi)
    return clipped.mean()

wins_mean = df.groupby('region').apply(winsorised_mean)
print('Winsorised mean by region:')
print(wins_mean)

Ventana móvil personalizada por grupo

Las ventanas móviles aplicadas al DataFrame completo ignoran los límites entre grupos. Si calcula una media móvil de 3 filas sobre una serie temporal que intercala dos productos, la ventana cruza incorrectamente los límites de los productos. Aplique la ventana móvil dentro de un groupby().apply() para garantizar que cada cálculo se mantenga dentro de su grupo; por ejemplo, para calcular la media móvil de ingresos de 3 meses por región.

def group_rolling_mean(group, window=3):
    group = group.sort_values('order_date').copy()
    group['rolling_revenue'] = group['revenue'].rolling(window, min_periods=1).mean()
    return group

# df_ts has order_date column
# df_rolled = df_ts.groupby('region').apply(group_rolling_mean).reset_index(drop=True)
print('Rolling window per group applied inside apply()')

Parámetro include_groups (Pandas 2.2+)

En Pandas 2.2 y versiones posteriores, groupby().apply() muestra un FutureWarning si las claves de agrupación aparecen en el DataFrame que recibe la función. Pase include_groups=False para excluir las columnas de agrupación del sub-DataFrame que se pasa a la función. Así evitará tanto la advertencia como las operaciones accidentales sobre las columnas clave dentro del cuerpo de la función.

def revenue_only(group):
    # group does not include 'region' column when include_groups=False
    return group['revenue'].sum()

# result = df.groupby('region').apply(revenue_only, include_groups=False)
print('include_groups=False avoids FutureWarning in Pandas 2.2+')

Combinar resultados de apply() con reset_index

Cuando groupby().apply() devuelve un DataFrame por grupo, el resultado tiene un MultiIndex que incluye la clave de grupo como nivel externo. Use reset_index(drop=True) para volver a convertir el índice en un rango entero simple. Como alternativa, use reset_index(level=0) para convertir la clave de grupo en una columna y hacerla explícita en la salida.

result = df.groupby('region').apply(top2_per_region)
print('With MultiIndex:')
print(result.head())

print('\nAfter reset_index:')
print(result.reset_index(drop=True))

Cuándo preferir transform() a apply()

groupby().apply() se utiliza para cálculos complejos a nivel de grupo que devuelven una forma distinta de la entrada. groupby().transform() se utiliza para cálculos que añaden una nueva columna alineada con el índice original, como devolver la media del grupo a cada fila para normalizarla. Use transform cuando necesite que el resultado tenga la misma forma que el DataFrame original; use apply cuando la forma del resultado sea diferente.

# transform: adds group mean back to each row
df['group_mean_revenue'] = df.groupby('region')['revenue'].transform('mean')

# apply: computes one scalar per group
group_totals = df.groupby('region')['revenue'].apply(sum)

print(df[['region', 'revenue', 'group_mean_revenue']])

Consejo de rendimiento: evite apply() para agregaciones sencillas

groupby().apply() es considerablemente más lento que groupby().agg() para operaciones sencillas, porque apply() crea un objeto completo de Python para cada grupo. Para sumas, medias y recuentos, use siempre agg(). Reserve apply() para los casos que realmente requieran el DataFrame completo del grupo: lógica condicional basada en varias columnas, estadísticas personalizadas o filtrado dentro de los grupos.

# SLOW: apply for simple sum
slow = df.groupby('region').apply(lambda g: g['revenue'].sum())

# FAST: native agg
fast = df.groupby('region')['revenue'].sum()

print('Both produce the same result:')
print(fast.equals(slow))

Comprobación rápida

Compruebe su comprensión de los conceptos de análisis de datos de esta lección.

Resumen de la lección

En esta lección ha aprendido: devolver escalares, Series y DataFrames desde groupby().apply(), calcular puntuaciones Z dentro de los grupos y estadísticas robustas personalizadas y elegir entre apply(), agg() y transform() para operaciones a nivel de grupo. A continuación, exploraremos map() y applymap() para realizar operaciones elemento a elemento en Series y DataFrames.

Preguntas frecuentes

¿La lección «apply() con GroupBy» es gratis?

Sí — el texto completo de «apply() con GroupBy» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Pandas & NumPy Academy, actualiza a CoddyKit PRO. El curso de Pandas & NumPy Academy incluye 4 lecciones en total.

¿Qué aprenderé en «apply() con GroupBy»?

Pase una función que opere sobre varias filas a groupby().apply() para calcular resúmenes complejos a nivel de grupo que agg() no puede expresar. Practicas Pandas & NumPy Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Pandas & NumPy Academy?

No se requiere experiencia previa. Pandas & NumPy Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «apply() con GroupBy»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Pandas & NumPy Academy?

Sí. Cada lección de Pandas & NumPy Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. apply() en columnas y filas
  2. apply() con GroupBy
  3. map() y applymap() para operaciones elemento a elemento
  4. Encadenamiento de métodos con pipe()
← Volver a Pandas & NumPy Academy