如何使用pd.shift正确计算分组下motooutstandingbalance逐周递减值
你现有代码的问题出在两点:
- 没有按
salesrepid分组执行位移操作,全局shift()会跨不同销售代表的行取值,导致组边界计算错误 - pandas的向量化列赋值是一次性计算所有行的结果,不会实时更新列值,后续行拿不到前面行刚计算出的最新余额,只能拿到原始值
正确实现步骤
首先必须保证你的数据已经按salesrepid和周维度字段排序,确保同一个销售代表的行是按时间先后顺序排列的,以下是两种可行方案:
方案1:分组累计求和(性能最优,适合大数据量)
import pandas as pd import numpy as np # 1. 排序:按销售代表ID+周字段升序排列,替换`week`为你实际的周/时间字段名 x = x.sort_values(by=['salesrepid', 'week']).reset_index(drop=True) # 2. 计算每个销售代表到上一行为止的累计扣款 x['cum_deduction'] = x.groupby('salesrepid')['actualmotordeductionfortheweek'].shift(1).cumsum() # 3. 用每个销售代表的初始余额减去累计扣款,得到当前行余额 x['motooutstandingbalance'] = x.groupby('salesrepid')['motooutstandingbalance'].transform('first') - x['cum_deduction'].fillna(0) # 4. 删除临时辅助列 x = x.drop('cum_deduction', axis=1)
方案2:分组逐行遍历(逻辑直观,适合小数据量)
# 1. 同方案1,先做排序 x = x.sort_values(by=['salesrepid', 'week']).reset_index(drop=True) # 2. 按销售代表分组逐行计算余额 def cal_balance(group): for idx in range(1, len(group)): group.iloc[idx, group.columns.get_loc('motooutstandingbalance')] = group.iloc[idx-1]['motooutstandingbalance'] - group.iloc[idx-1]['actualmotordeductionfortheweek'] return group x = x.groupby('salesrepid', group_keys=False).apply(cal_balance)
注意:如果你的数据中
salesrepid的第一行motooutstandingbalance已经是正确的初始值,上述代码可以直接运行,否则需要先给每个组的第一行填充正确的初始余额。
内容的提问来源于stack exchange,提问作者Tito Lulu
相关产品推荐
相关产品推荐

