大家好,在数据分析中,需要对数据进行分组统计与计算,Pandas的groupby
功能提供了强大的分组功能。transform
方法是groupby
中常用的转换方法之一,它允许在分组的基础上进行灵活的转换和计算,并将结果与原始数据保持相同的结构。因此,transform
非常适合需要将计算结果返回到原始DataFrame的情况。
1.transform方法基本概念
transform
方法可以对每个分组进行计算,并将结果“广播”回原始DataFrame,使得返回的DataFrame形状与原始数据一致。与其他groupby
操作不同,transform
返回的数据不会改变原始DataFrame的行数,而是将分组后的计算结果逐行赋值给原始DataFrame。
transform
方法的基本语法如下:
DataFrame.groupby('列名')['列名'].transform(func)
-
groupby('列名')
:指定需要分组的列。 -
transform(func)
:对每个分组应用函数func
,可以是内置的聚合函数,也可以是自定义函数。
常见的聚合函数包括求均值(mean
)、求和(sum
)、最大值(max
)、最小值(min
)等。
2.示例数据集
使用一个包含员工信息的示例数据集,包括员工姓名、部门和薪资信息,方便演示各种transform
操作。
import pandas as pd# 创建示例数据集
data = {'姓名': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'],'部门': ['销售', '销售', 'IT', 'IT', '市场', '市场'],'薪资': [7000, 6800, 9000, 8500, 7500, 7700]
}
df = pd.DataFrame(data)
print("原始数据集:\n", df)
结果如下所示:
姓名 部门 薪资
0 Alice 销售 7000
1 Bob 销售 6800
2 Charlie IT 9000
3 David IT 8500
4 Eve 市场 7500
5 Frank 市场 7700
3.分组计算并广播结果
假设希望计算每个部门的平均薪资,并将该值赋予每位员工。使用transform
方法可以实现这点,计算部门平均薪资并广播:
# 使用 transform 计算每个部门的平均薪资
df['部门平均薪资'] = df.groupby('部门')['薪资'].transform('mean')
print("部门平均薪资:\n", df)
结果如下所示:
姓名 部门 薪资 部门平均薪资
0 Alice 销售 7000 6900.0
1 Bob 销售 6800 6900.0
2 Charlie IT 9000 8750.0
3 David IT 8500 8750.0
4 Eve 市场 7500 7600.0
5 Frank 市场 7700 7600.0
在这个示例中,transform('mean')
计算了每个部门的平均薪资,并将计算结果广播回原始DataFrame的每一行中。
4.使用自定义函数进行转换
transform
不仅支持常规的聚合函数,还支持自定义函数。假设计算每位员工的薪资与部门平均薪资的差异,可以使用自定义函数实现。
# 自定义函数计算薪资与部门平均薪资的差异
df['薪资差异'] = df.groupby('部门')['薪资'].transform(lambda x: x - x.mean())
print("薪资差异:\n", df)
结果如下所示:
姓名 部门 薪资 部门平均薪资 薪资差异
0 Alice 销售 7000 6900.0 100.0
1 Bob 销售 6800 6900.0 -100.0
2 Charlie IT 9000 8750.0 250.0
3 David IT 8500 8750.0 -250.0
4 Eve 市场 7500 7600.0 -100.0
5 Frank 市场 7700 7600.0 100.0
通过自定义lambda
函数,计算了每位员工的薪资差异,进一步揭示了员工与部门平均水平的偏差情况。
5.transform与apply的区别
transform
:返回的结果与原始DataFrame的形状一致,每个分组的计算结果会逐行赋值给原DataFrame。
apply
:通常返回缩小后的DataFrame,适合整体的分组操作。
以下示例展示了apply
与transform
的差异:
# 使用 apply 计算每个部门的薪资均值
df_apply = df.groupby('部门')['薪资'].apply(lambda x: x.mean())
print("使用 apply 结果:\n", df_apply)
结果如下所示:
部门
IT 8750.0
市场 7600.0
销售 6900.0
Name: 薪资, dtype: float64
apply
直接返回分组后的平均薪资,而transform
会将分组后的均值按行赋回原DataFrame。transform
的输出与原DataFrame形状一致,因此适合需要广播结果的计算。
6.transform方法的高级应用
6.1 计算每位员工的部门排名
可以使用transform
和rank
函数计算每位员工在其部门内的薪资排名:
# 计算每位员工的部门薪资排名
df['部门薪资排名'] = df.groupby('部门')['薪资'].transform('rank', ascending=False)
print("部门薪资排名:\n", df)
结果如下所示:
姓名 部门 薪资 部门平均薪资 薪资差异 部门薪资排名
0 Alice 销售 7000 6900.0 100.0 1.0
1 Bob 销售 6800 6900.0 -100.0 2.0
2 Charlie IT 9000 8750.0 250.0 1.0
3 David IT 8500 8750.0 -250.0 2.0
4 Eve 市场 7500 7600.0 -100.0 2.0
5 Frank 市场 7700 7600.0 100.0 1.0
在这个示例中,transform('rank')
计算了每位员工在其部门内的薪资排名。
6.2 归一化处理:按部门归一化薪资
归一化处理通常用于数据预处理,使数据更加集中和标准化。以下代码展示如何按部门对薪资进行归一化:
# 按部门归一化薪资
df['归一化薪资'] = df.groupby('部门')['薪资'].transform(lambda x: (x - x.min()) / (x.max() - x.min()))
print("按部门归一化薪资:\n", df)
结果如下所示:
姓名 部门 薪资 部门平均薪资 薪资差异 部门薪资排名 归一化薪资
0 Alice 销售 7000 6900.0 100.0 1.0 1.0
1 Bob 销售 6800 6900.0 -100.0 2.0 0.0
2 Charlie IT 9000 8750.0 250.0 1.0 1.0
3 David IT 8500 8750.0 -250.0 2.0 0.0
4 Eve 市场 7500 7600.0 -100.0 2.0 0.0
5 Frank 市场 7700 7600.0 100.0 1.0 1.0
在这个示例中,使用lambda
函数实现了归一化操作 (x - x.min()) / (x.max() - x.min())
,将每个部门的薪资归一化到[0, 1]区间。归一化后的薪资可以更直观地比较不同部门内部的薪资差异。
6.3 标准化处理:按部门标准化薪资
标准化是数据预处理中的另一种常用方法,通常用于使数据符合正态分布。以下代码展示如何按部门对薪资进行标准化:
# 按部门标准化薪资
df['标准化薪资'] = df.groupby('部门')['薪资'].transform(lambda x: (x - x.mean()) / x.std())
print("按部门标准化薪资:\n", df)
结果如下所示:
姓名 部门 薪资 部门平均薪资 薪资差异 部门薪资排名 归一化薪资 标准化薪资
0 Alice 销售 7000 6900.0 100.0 1.0 1.0 0.707
1 Bob 销售 6800 6900.0 -100.0 2.0 0.0 -0.707
2 Charlie IT 9000 8750.0 250.0 1.0 1.0 0.707
3 David IT 8500 8750.0 -250.0 2.0 0.0 -0.707
4 Eve 市场 7500 7600.0 -100.0 2.0 0.0 -0.707
5 Frank 市场 7700 7600.0 100.0 1.0 1.0 0.707
在这个示例中,使用transform
方法对每个部门的薪资进行标准化处理 (x - x.mean()) / x.std()
,从而将数据转换为均值为0、标准差为1的分布,方便不同部门之间的薪资比较。
transform
方法为Pandas的分组操作提供了强大的支持,适用于在分组基础上进行灵活的逐行计算和结果广播。本文通过实例展示transform
的基本用法、自定义函数的应用、分组排名、归一化和标准化等场景。通过掌握transform
的使用技巧,可以使数据处理和分析更加高效和灵活。