Función Pandas groupby-transform()
groupby.transform()Es una función de Pandas para transformar datos después de agrupar. A diferencia de las funciones de agregación,la agregación devuelve un resumen de cada grupo, mientras que la transformación devuelve un resultado de la misma longitud que los datos originales.。
En términos simples,transform()transmite (broadcast) el resultado del cálculo del grupo a cada fila de los datos originales. Esto es muy útil en escenarios como calcular la posición relativa de cada miembro dentro de su grupo, la estandarización dentro del grupo y la diferencia respecto a la media del grupo.
Sintaxis básica y parámetros
transform()Es una función miembro del objeto GroupBy; primero se debe usargroupby()y llamarla después de agrupar.
Formato de sintaxis
GroupBy.transform(func, axis=0, *args, engine=None, engine_kwargs=None, **kwargs)
Descripción de parámetros
| Parámetro | Tipo | Descripción | Valor predeterminado |
|---|---|---|---|
| func | str, list, dict o callable | Función de transformación. Puede ser el nombre de una función integrada (como 'mean', 'sum', 'std'), una lista de funciones, un diccionario que especifica diferentes funciones para cada columna, o una función personalizada. | None |
| axis | int | Dirección del eje sobre el que se aplica la transformación; 0 indica por filas (dimensión de agrupación), 1 indica por columnas. | 0 |
| args | tuple | Argumentos posicionales adicionales que se pasan a la función de transformación. | () |
| engine | str | Especifica el motor de cálculo; puede ser 'cython' o 'numba'. None indica que Pandas lo selecciona automáticamente. | None |
| engine_kwargs | dict | Diccionario de argumentos adicionales para pasar al motor subyacente. | None |
Valor de retorno
- Tipo de retorno:
SeriesoDataFrame - Descripción: Devuelve un resultado con el mismo número de filas que los datos originales. Cada fila de datos original recibe el resultado del cálculo de su grupo correspondiente.
Ejemplos
Vamos a dominar por completo, mediante una serie de ejemplos de simples a complejos,groupby.transform()el uso de esta función.
Ejemplo 1: Uso básico - Calcular la media dentro del grupo
transform()El uso más básico es calcular la media de cada grupo y luego transmitir (broadcast) el resultado de vuelta a cada fila.
Ejemplo
# Crear datos de calificaciones de estudiantes
data = {
'Nombre': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
'Clase': ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'A'],
Lengua china: [85, 92, 78, 88, 95, 82, 90, 87],
Matemáticas: [90, 85, 92, 78, 88, 91, 85, 89]
}
# Crear DataFrame
df = pd.DataFrame(data)
print(Datos de calificaciones de estudiantes:)
print(df)
print()
# Calcular el promedio de matemáticas de cada clase y luego transmitirlo a cada fila
df[Promedio de matemáticas de la clase] = df.groupby('Clase')[Matemáticas].transform('mean')
# Calcular la diferencia entre la calificación de cada estudiante y el promedio de la clase.
df[Diferencia respecto al promedio] = df[Matemáticas] - df[Promedio de matemáticas de la clase]
print("Datos después de añadir el promedio de la clase y la diferencia:")
print(df)
print()
# Calcular simultáneamente el promedio por clase de varias columnas
df[[Promedio de chino de la clase, 'promedio de matemáticas de la clase 2']] = df.groupby('Clase')[[Lengua china, Matemáticas]].transform('mean')
print(Datos después de agregar los promedios de varias columnas:)
print(df)
Resultado de la ejecución:
学生成绩数据: 姓名 班级 语文 数学 0 张三 A 85 90 1 李四 A 92 85 2 王五 A 78 92 3 赵六 B 88 78 4 孙七 B 95 88 5 周八 B 82 91 6 吴九 B 90 85 7 郑十 A 87 89 添加班级平均分和差值后的数据: 姓名 班级 语文 数学 班级数学平均分 与平均分差值 0 张三 A 85 90 89.000000 1.000000 1 李四 A 92 85 89.000000 -4.000000 2 王五 A 78 92 89.000000 3.000000 3 赵六 B 88 78 85.666667 -7.666667 4 孙七 B 95 88 85.666667 2.333333 5 周八 B 82 91 85.666667 5.333333 6 吴九 B 90 85 85.666667 -0.666667 7 郑十 A 87 89 89.000000 0.000000 添加多列平均值后的数据: 姓名 班级 语文 数学 班级语文平均分 班级数学平均分2 0 张三 A 85 90 85.500000 89.0 1 李四 A 92 85 85.500000 89.0 2 王五 A 78 92 85.500000 89.0 3 赵六 B 88 78 88.750000 85.5 4 孙七 B 95 88 88.750000 85.5 5 周八 B 82 91 88.750000 85.5 6 吴九 B 90 85 88.750000 85.5 7 郑十 A 87 89 85.500000 89.0
Análisis del código:
transform('mean')Se calcula la media de matemáticas de cada clase.- Dado que Zhang San, Li Si, Wang Wu y Zheng Shi están todos en la clase A, el "promedio de matemáticas de la clase" que obtienen es el promedio de las calificaciones de matemáticas de la clase A.
- La longitud del valor de retorno es la misma que el número de filas de los datos originales; esta es la diferencia clave entre transform y agg.
Ejemplo 2: Estandarización dentro del grupo (Z-Score)
transform()transform se usa a menudo para calcular valores estandarizados dentro del grupo, lo cual es muy útil al comparar la posición relativa de un individuo dentro de su grupo.
Ejemplo
# Crear datos de salario de los empleados
data = {
'Nombre': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
'Departamento': [Ventas, Ventas, Ventas, 'Tecnología', 'Tecnología', 'Tecnología', Administración, Administración],
'Salario': [5000, 8000, 6000, 9000, 12000, 10000, 4500, 7000]
}
df = pd.DataFrame(data)
print(Datos de salarios de empleados:)
print(df)
print()
# Calcula el Z-Score (puntuación estandarizada) del salario de cada empleado dentro del departamento
# Z-Score = (valor original - media del grupo) / desviación estándar del grupo
df[Salario promedio del departamento] = df.groupby('Departamento')['Salario'].transform('mean')
df[Desviación estándar de salarios del departamento] = df.groupby('Departamento')['Salario'].transform('std')
df['Z-Score'] = (df['Salario'] - df[Salario promedio del departamento]) / df[Desviación estándar de salarios del departamento]
print("Datos después de añadir las estadísticas por departamento y el Z-Score:")
print(df)
print()
# Usar una función personalizada para calcular el Z-Score de una vez
def z_score(x):
"""Calcular Z-Score"""
return (x - x.mean()) / x.std()
df['Z-Score2'] = df.groupby('Departamento')['Salario'].transform(z_score)
print("Z-Score calculado con una función personalizada:")
print(df[['Nombre', 'Departamento', 'Salario', 'Z-Score2']])
Resultado de la ejecución:
员工工资数据: 姓名 部门 工资 0 张三 销售 5000 1 李四 销售 8000 2 王五 销售 6000 3 赵六 技术 9000 4 孙七 技术 12000 5 周八 技术 10000 6 吴九 行政 4500 7 郑十 行政 7000 添加部门统计和Z-Score后的数据: 姓名 部门 工资 部门平均工资 部门工资标准差 Z-Score 0 张三 销售 5000 6333.333333 1525.755 -0.872871 1 李四 销售 8000 6333.333333 1525.755 1.092091 2 王五 销售 6000 6333.333333 1525.755 -0.218218 3 赵六 技术 9000 10333.333333 1525.755 -0.872871 4 孙七 技术 12000 10333.333333 1525.755 1.092091 5 周八 技术 10000 10333.333333 1525.755 -0.218218 6 吴九 行政 4500 5750.000000 1767.767 -0.707107 7 郑十 行政 7000 5750.000000 1767.767 0.707107 使用自定义函数计算的 Z-Score: 姓名 部门 工资 Z-Score2 0 张三 销售 5000 -0.872871 1 李四 销售 8000 1.092091 2 王五 销售 6000 -0.218218 3 赵六 技术 9000 -0.872871 4 孙七 技术 12000 1.092091 5 周八 技术 10000 -0.218218 6 吴九 行政 4500 -0.707107 7 郑十 行政 7000 0.707107
Análisis del código:
- El Z-Score indica el número de desviaciones estándar que el valor original está alejado de la media; un valor positivo indica que está por encima de la media, y un valor negativo que está por debajo de la media.
- Mediante el Z-Score, se puede eliminar el efecto de las diferencias en los niveles salariales entre departamentos y comparar la posición relativa de los empleados dentro de su departamento.
- El Z-Score de Zhang San es -0.87, lo que indica que su salario está aproximadamente 0.87 desviaciones estándar por debajo del nivel promedio del departamento de ventas.
Ejemplo 3: Ranking y percentil dentro del grupo
transform()transform también se puede usar para calcular la clasificación dentro del grupo, lo cual es muy útil en ordenamiento y análisis de competencia.
Ejemplo
import numpy as np
# Crear datos de calificaciones de estudiantes
data = {
'Nombre': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba, Wu Jiu, Zheng Shi],
'Clase': ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'A'],
Matemáticas: [90, 85, 92, 78, 88, 91, 85, 89]
}
df = pd.DataFrame(data)
print(Datos de calificaciones de estudiantes:)
print(df)
print()
# Calcular la clasificación de cada estudiante en la clase (de mayor a menor)
df[Ranking dentro de la clase] = df.groupby('Clase')[Matemáticas].transform(lambda x: x.rank(ascending=False))
# Calcular el percentil de cada estudiante dentro de la clase (rango porcentual)
df[Percentil dentro de la clase] = df.groupby('Clase')[Matemáticas].transform(lambda x: x.rank(pct=True))
print(Datos después de agregar el rango dentro de la clase y el percentil:)
print(df)
print()
# Otra forma de rellenar valores faltantes: usar la media del grupo
data_with_na = {
'Nombre': ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu', Sun Qi, Zhou Ba],
'Clase': ['A', 'A', 'A', 'B', 'B', 'B'],
'Calificaciones': [85, np.nan, 78, 88, np.nan, 82]
}
df_na = pd.DataFrame(data_with_na)
print(Datos con valores faltantes:)
print(df_na)
print()
# Rellenar los valores faltantes con la media del grupo
df_na[Calificaciones después del relleno] = df_na.groupby('Clase')['Calificaciones'].transform(lambda x: x.fillna(x.mean()))
print(Resultado tras imputar con la media del grupo:)
print(df_na)
Resultado de la ejecución:
学生成绩数据: 姓名 班级 数学 0 张三 A 90 1 李四 A 85 2 王五 A 92 3 赵六 B 78 4 孙七 B 88 5 周八 B 91 6 吴九 B 85 7 郑十 A 89 添加班级内排名和百分位后的数据: 姓名 班级 数学 班级内排名 班级内百分位 0 张三 A 90 2.0 0.666667 1 李四 A 85 3.0 1.000000 2 王五 A 92 1.0 1.000000 3 赵六 B 78 4.0 0.250000 4 孙七 B 88 2.0 0.500000 5 周八 B 91 1.0 0.750000 6 吴九 B 85 3.0 0.500000 7 郑十 A 89 4.0 0.333333 包含缺失值的数据: 姓名 班级 成绩 0 张三 A 85.0 1 李四 A NaN 2 王五 A 78.0 3 赵六 B 88.0 4 孙七 B NaN 5 周八 B 82.0 使用组内均值填充后的结果: 姓名 班级 成绩 填充后的成绩 0 张三 A 85.0 85.0 1 李四 A NaN 81.5 2 王五 A 78.0 78.0 3 赵六 B 88.0 88.0 4 孙七 B NaN 85.0 5 周八 B 82.0 82.0
Análisis del código:
rank(ascending=False)Se calcula la clasificación; los valores más altos se colocan al frente.rank(pct=True)Se calcula el ranking percentil; el resultado está entre 0 y 1.transform(lambda x: x.fillna(x.mean()))Es un patrón común para manejar valores faltantes: se usa la media de cada grupo para rellenar los valores faltantes dentro de ese grupo.
Ejemplo 4: Usar una función de transformación personalizada
transform()Se admiten funciones personalizadas, que pueden implementar lógica de transformación de datos dentro de los grupos más compleja.
Ejemplo
import numpy as np
# Crear datos de precios de acciones
data = {
'Código de la acción': ['AAPL', 'AAPL', 'AAPL', 'AAPL', 'GOOG', 'GOOG', 'GOOG', 'GOOG'],
'Fecha': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'] * 2,
'Precio de cierre': [100, 105, 102, 110, 80, 85, 82, 90]
}
df = pd.DataFrame(data)
print("Datos de precios de acciones:")
print(df)
print()
# Función personalizada: calcular la tasa de rendimiento diaria de cada acción
def calc_daily_return(prices):
"""Calcular la tasa de rendimiento diaria: (precio de hoy - precio de ayer) / precio de ayer"""
return prices.pct_change()
# Calcular la tasa de rendimiento diaria de cada acción
df['Tasa de rendimiento diaria'] = df.groupby('Código de la acción')['Precio de cierre'].transform(calc_daily_return)
print("Datos después de agregar la tasa de rendimiento diaria:")
print(df)
print()
# Función personalizada: calcular la normalización entre el máximo y el mínimo dentro del grupo
def normalize(x):
"""Normalización: (x - min) / (max - min)"""
return (x - x.min()) / (x.max() - x.min())
# Calcular el valor normalizado del precio de cada acción
df['Precio normalizado'] = df.groupby('Código de la acción')['Precio de cierre'].transform(normalize)
print("Datos después de agregar el precio normalizado:")
print(df)
Resultado de la ejecución:
股票价格数据: 股票代码 日期 收盘价 0 AAPL 2024-01-01 100 1 AAPL 2024-01-02 105 2 AAPL 2024-01-03 102 3 AAPL 2024-01-04 110 4 GOOG 2024-01-01 80 5 GOOG 2024-01-02 85 6 GOOG 2024-01-03 82 7 GOOG 2024-01-04 90 添加日收益率后的数据: 股票代码 日期 收盘价 日收益率 0 AAPL 2024-01-01 100 NaN 1 AAPL 2024-01-02 105 0.050000 2 AAPL 2024-01-03 102 -0.028571 3 AAPL 2024-01-04 110 0.078431 4 GOOG 2024-01-01 80 NaN 5 GOOG 2024-01-02 85 0.062500 6 GOOG 2024-01-03 82 -0.035294 7 GOOG 2024-01-04 90 0.097561 添加归一化价格后的数据: 股票代码 日期 收盘价 日收益率 归一化价格 0 AAPL 2024-01-01 100 NaN 0.000000 1 AAPL 2024-01-02 105 0.050000 0.500000 2 AAPL 2024-01-03 102 -0.028571 0.200000 3 AAPL 2024-01-04 110 0.078431 1.000000 4 GOOG 2024-01-01 80 NaN 0.000000 5 GOOG 2024-01-02 85 0.062500 0.500000 6 GOOG 2024-01-03 82 -0.035294 0.200000 7 GOOG 2024-01-04 90 0.097561 1.000000
Análisis del código:
- La función de transformación recibe una Series (los datos dentro de cada grupo).
- La longitud de la Series devuelta debe ser igual a la longitud de la Series de entrada.
- El primer valor es NaN porque
pct_change()se calcula un cambio relativo y el primer día no hay datos del día anterior.
Diferencia clave:
agg()ytransform()La diferencia radica en:agg()devuelve el resultado resumido de cada grupo (el número de filas es igual al número de grupos), mientras quetransform()devuelve un resultado con la misma longitud que los datos originales. Regla mnemotécnica: agg comprime los datos, transform mantiene la forma de los datos.
Otras extensiones
Funciones comunes de Pandas