Python DataFrame中按类别品牌分组替换低销量值为组内有效均值
解决方案:按分组排除自身后插补低销量值
我来给你一个精准匹配需求的实现方案,用Pandas就能轻松搞定这个插补任务。
核心思路
我们需要针对Sales小于20的记录,替换为同Category+Brand分组下,排除当前这条低销量值后的Sales均值。关键在于计算分组均值时要排除当前行本身,而不是直接用整个分组的均值。
完整代码实现
1. 导入依赖并构造示例数据
首先先准备好测试用的DataFrame,和你给出的示例结构一致:
import pandas as pd # 构造示例数据 data = { 'Category': ['Food', 'Food', 'Food', 'Cream', 'Cream', 'Cream'], 'Brand': ['pp', 'pp', 'pp', 'xy', 'xy', 'xy'], 'Sales': [100, 200, 10, 40, 2, 60] } Transactions = pd.DataFrame(data)
2. 实现分组排除自身的均值计算
定义一个辅助函数,用来计算每个分组中排除当前行后的均值,再结合groupby.transform为每一行生成对应的插补值:
def get_group_mean_without_self(group): group_total = group.sum() group_size = len(group) # 处理分组只有1行的边界情况(避免除以0) if group_size == 1: return group # 可以根据业务需求改成其他默认值,比如0或者全局Sales均值 # 总和减去当前行的值,再除以(分组大小-1)就是排除自身后的均值 return (group_total - group) / (group_size - 1) # 按Category和Brand分组,生成每个行对应的插补候选值 Transactions['temp_impute_val'] = Transactions.groupby(['Category', 'Brand'])['Sales'].transform(get_group_mean_without_self) # 替换Sales<20的记录,其他保留原值 Transactions['Sales'] = Transactions.apply( lambda row: row['temp_impute_val'] if row['Sales'] < 20 else row['Sales'], axis=1 ) # 清理临时列 Transactions = Transactions.drop('temp_impute_val', axis=1)
3. 处理后的结果
运行完代码后,你的DataFrame会变成这样:
| Category | Brand | Sales |
|---|---|---|
| Food | pp | 100.0 |
| Food | pp | 200.0 |
| Food | pp | 150.0 |
| Cream | xy | 40.0 |
| Cream | xy | 50.0 |
| Cream | xy | 60.0 |
完全符合你要求的插补结果:Food-pp组的10被替换成(100+200)/2=150,Cream-xy组的2被替换成(40+60)/2=50。
边界情况说明
如果某个Category+Brand分组只有1条记录,且这条记录的Sales<20,我们的代码会保留原数值(你可以根据业务需求修改get_group_mean_without_self函数里的默认返回值,比如改成全局Sales的均值)。
内容的提问来源于stack exchange,提问作者Mighty
相关产品推荐
相关产品推荐

