模块四-数据转换与操作——28. 分组变换与过滤 28. 分组变换与过滤1. 概述除了聚合agg之外groupby 还支持**变换transform和过滤filter**操作。transform 用于在组内进行元素级运算filter 用于根据组属性筛选组。importpandasaspdimportnumpyasnp# 创建示例数据np.random.seed(42)dfpd.DataFrame({部门:[技术,销售,技术,市场,销售,技术,市场,销售,技术,市场],姓名:[f员工_{i}foriinrange(1,11)],工资:[8000,12000,10000,15000,11000,9500,10500,12500,9000,13000],年龄:[25,30,28,32,35,27,29,31,26,33]})print(原始数据:)print(df)2. transform() 变换2.1 什么是 transformtransform返回与原始数据相同形状的结果而agg返回的是聚合后的结果。# agg 返回聚合结果形状改变agg_resultdf.groupby(部门)[工资].mean()print(agg 结果:)print(agg_result)print(fagg 形状:{agg_result.shape})# transform 返回相同形状transform_resultdf.groupby(部门)[工资].transform(mean)print(\ntransform 结果:)print(transform_result)print(ftransform 形状:{transform_result.shape})2.2 常用 transform 操作# 计算组内均值df[部门平均工资]df.groupby(部门)[工资].transform(mean)print(部门平均工资:)print(df[[部门,姓名,工资,部门平均工资]])# 计算组内标准差df[部门工资标准差]df.groupby(部门)[工资].transform(std)# 计算组内排名df[组内排名]df.groupby(部门)[工资].transform(rank,ascendingFalse)print(\n组内排名:)print(df[[部门,姓名,工资,组内排名]])2.3 标准化Z-Score# 组内标准化df[工资标准化]df.groupby(部门)[工资].transform(lambdax:(x-x.mean())/x.std())print(组内标准化:)print(df[[部门,姓名,工资,工资标准化]])2.4 计算与均值的差值# 计算与组均值的差值df[与均值差额]df[工资]-df.groupby(部门)[工资].transform(mean)print(与均值差额:)print(df[[部门,姓名,工资,与均值差额]])2.5 填充组内缺失值# 创建包含缺失值的数据df_nadf.copy()df_na.loc[[1,5],工资]np.nanprint(包含缺失值的数据:)print(df_na)# 用组内均值填充df_na[工资_filled]df_na.groupby(部门)[工资].transform(lambdax:x.fillna(x.mean()))print(\n填充后:)print(df_na[[部门,工资,工资_filled]])3. filter() 过滤3.1 基本用法filter根据组属性筛选组返回满足条件的组的所有行。# 筛选员工数 3 的部门filtereddf.groupby(部门).filter(lambdax:len(x)3)print(员工数 3 的部门:)print(filtered)# 筛选平均工资 10000 的部门filtereddf.groupby(部门).filter(lambdax:x[工资].mean()10000)print(\n平均工资 10000 的部门:)print(filtered)3.2 条件过滤# 筛选最高工资 12000 的部门filtereddf.groupby(部门).filter(lambdax:x[工资].max()12000)print(有员工工资 12000 的部门:)print(filtered)# 筛选最低工资 9000 的部门filtereddf.groupby(部门).filter(lambdax:x[工资].min()9000)print(\n有员工工资 9000 的部门:)print(filtered)# 筛选工资方差 500000 的部门filtereddf.groupby(部门).filter(lambdax:x[工资].var()500000)print(\n工资方差 500000 的部门:)print(filtered)4. transform vs agg vs filter 对比方法返回值形状用途agg聚合后的形状每组一行计算组统计量transform与原数据相同形状组内元素级运算filter满足条件的组的所有行筛选组# 对比示例print(原始数据形状:,df.shape)print(agg 结果形状:,df.groupby(部门)[工资].mean().shape)print(transform 结果形状:,df.groupby(部门)[工资].transform(mean).shape)print(filter 结果形状:,df.groupby(部门).filter(lambdax:len(x)3).shape)5. 完整示例员工绩效分析# 创建员工数据np.random.seed(42)employeespd.DataFrame({部门:np.random.choice([技术,销售,市场,人事],100),姓名:[f员工_{i}foriinrange(1,101)],工资:np.random.randint(5000,20000,100),绩效分:np.random.uniform(60,100,100).round(1),工龄:np.random.randint(1,15,100)})print(*60)print(员工绩效分析transform filter)print(*60)print(\n原始数据:)print(employees.head())# 1. 添加组内统计列print(\n1. 添加组内统计:)employees[部门平均工资]employees.groupby(部门)[工资].transform(mean)employees[部门平均绩效]employees.groupby(部门)[绩效分].transform(mean)employees[部门人数]employees.groupby(部门)[姓名].transform(count)employees[组内排名]employees.groupby(部门)[绩效分].transform(rank,ascendingFalse)print(employees[[部门,姓名,绩效分,组内排名,部门平均绩效]].head(10))# 2. 计算与平均值的差距print(\n2. 绩效差距分析:)employees[绩效差距]employees[绩效分]-employees[部门平均绩效]print(employees[[部门,姓名,绩效分,部门平均绩效,绩效差距]].head(10))# 3. 筛选部门平均绩效 80print(\n3. 平均绩效 80 的部门:)high_perf_deptsemployees.groupby(部门).filter(lambdax:x[绩效分].mean()80)print(f筛选前行数:{len(employees)})print(f筛选后行数:{len(high_perf_depts)})print(筛选后的部门分布:)print(high_perf_depts[部门].value_counts())# 4. 筛选部门人数 20print(\n4. 人数 20 的部门:)large_deptsemployees.groupby(部门).filter(lambdax:len(x)20)print(large_depts[部门].value_counts())# 5. 标准化绩效分print(\n5. 组内标准化绩效:)employees[标准化绩效]employees.groupby(部门)[绩效分].transform(lambdax:(x-x.mean())/x.std())print(employees[[部门,姓名,绩效分,标准化绩效]].head(10))# 6. 标记优秀员工组内前20%deftop_20_percent(x):thresholdx.quantile(0.8)returnxthreshold employees[是否优秀]employees.groupby(部门)[绩效分].transform(top_20_percent)print(\n6. 各部门优秀员工:)print(employees[employees[是否优秀]][[部门,姓名,绩效分]].head(10))6. transform 常用函数函数说明示例mean()组内均值df.groupby(A)[B].transform(mean)sum()组内和df.groupby(A)[B].transform(sum)std()组内标准差df.groupby(A)[B].transform(std)rank()组内排名df.groupby(A)[B].transform(rank)cumsum()组内累计和df.groupby(A)[B].transform(cumsum)fillna()填充缺失值df.groupby(A)[B].transform(lambda x: x.fillna(x.mean()))自定义函数任意运算df.groupby(A)[B].transform(lambda x: x - x.mean())7. 总结操作方法返回值示例组内均值transform(mean)同形状df.groupby(A)[B].transform(mean)组内排名transform(rank)同形状df.groupby(A)[B].transform(rank)组内标准化transform(lambda x: (x-x.mean())/x.std())同形状df.groupby(A)[B].transform(lambda x: (x-x.mean())/x.std())组内累计transform(cumsum)同形状df.groupby(A)[B].transform(cumsum)筛选组filter(lambda x: condition)满足条件的行df.groupby(A).filter(lambda x: len(x) 3)筛选组均值条件filter(lambda x: x[B].mean() threshold)满足条件的行df.groupby(A).filter(lambda x: x[B].mean() 50)