Pandas groupby分组后如何创建布尔列并按条件计算Salary
pandas分组内计算布尔列并完成组内值累加方案
问题复现与错误点说明
现有名为data的DataFrame,需要按['ID','Month']字段拆分分组,所有计算严格限制在组内执行,禁止跨组运算:
- 第一步在组内通过行移位计算布尔列
B,判断规则为(当前行O值 == 下一行D值) | (当前行D值 == 上一行O值) - 第二步在每个分组内,将
B=False行的Salary值,累加到同组所有B=True的行上
示例数据构造代码:
import pandas as pd data_ = {'ID': [777, 777, 777,777,777,777],'Month':[1,1,1,2,2,2], 'Salary': [130,170,50,140,180,60], 'O': ["ACC","BRU","BRU","ACC","BRU","BRU"], 'D':["LFW","ACC","LFW","LFW","ACC","LFW"]} data = pd.DataFrame(data=data_)
原有代码的两个核心错误:
- 孤立调用
data.groupby(['ID','Month'])没有赋值给变量,后续shift是直接在全表执行,移位时会跨组取到其他分组的行数据 - 拆分
B=True/B=False子集后直接做加法,没有按分组匹配对应值,会出现索引错位、跨组累加的问题
注意:pandas中单独调用
groupby()不会修改原表,也不会让后续的全表操作自动应用分组规则,必须将分组结果赋值给变量,所有组内运算都通过该分组对象调用,才能保证运算不跨组。
正确实现代码
1. 组内计算B列
所有移位操作基于分组对象调用,组边界的行移位后返回空值,不会跨组取数:
# 生成分组对象,后续所有组内运算都基于该对象执行 grp = data.groupby(['ID', 'Month']) # 组内取上一行O值、下一行D值 prev_O = grp['O'].shift(1) next_D = grp['D'].shift(-1) # 计算B列 data['B'] = (data['O'] == next_D) | (data['D'] == prev_O)
2. 组内完成Salary累加
先按组统计B=False行的薪资总和,再将总和分配到同组B=True的行上,以下代码默认将False行薪资平均分配给同组所有True行,如果需要每个True行都加False行的总薪资,去掉代码里除以True行数的逻辑即可:
# 按组统计B=False的薪资总和 false_sal_sum = data.loc[~data['B']].groupby(['ID', 'Month'])['Salary'].sum() # 按组统计B=True的行数 true_row_cnt = data.loc[data['B']].groupby(['ID', 'Month'])['B'].count() # 计算每个True行需要累加的薪资值,无True行的组填0避免报错 add_value = (false_sal_sum / true_row_cnt).fillna(0) # 匹配回原表,非True行累加值填0 data['add_sal'] = data.set_index(['ID','Month']).index.map(add_value.get).fillna(0) # 仅对B=True的行做薪资累加 data.loc[data['B'], 'Salary'] += data.loc[data['B'], 'add_sal'] # 删除临时列 data = data.drop(columns='add_sal')
结果验证
执行完上述代码后打印data,结果符合预期:每个ID+Month分组共3行,中间行B为True,累加同组首尾两行False的薪资后,1月分组True行薪资为170+130+50=350,2月分组True行薪资为180+140+60=380。
如果数据量较大,上述map匹配方案比循环逐行处理性能高1~2个数量级,适合百万级以上数据集。
内容的提问来源于stack exchange,提问作者the phoenix
相关产品推荐
相关产品推荐

