基于月度限额的部门预算月度分配计算问题(Python Pandas)
问题分析
你的代码只填充第一个NaN的原因是:Pandas的列赋值是一次性计算,无法迭代更新AMT_ALLOC_MONTH列的状态。当你第一次计算时,只有第一个NaN被填充,但后续行的cumsum仍基于原始的NaN值,ffill会直接复制第一个填充值,导致后续分配额重复,无法正确计算剩余预算。
解决方案
下面提供两种高效的实现方式,前提是你的DataFrame已按DEPT和月份列(比如MONTH)排序,确保月份顺序正确。
方法1:分组循环计算(直观易维护)
通过groupby对每个部门单独处理,逐行计算剩余预算并分配金额:
import pandas as pd # 确保数据按部门和月份排序(替换MONTH为你的月份列名) table = table.sort_values(['DEPT', 'MONTH']) def calculate_monthly_alloc(group): # 获取部门总预算和月度限额(假设每个部门的AMT_TOTAL/LIMIT_MONTH是固定值) total_budget = group['AMT_TOTAL'].iloc[0] monthly_limit = group['LIMIT_MONTH'].iloc[0] remaining = total_budget allocations = [] for _ in range(len(group)): if remaining <= 0: allocations.append(0.0) else: current_alloc = min(remaining, monthly_limit) allocations.append(current_alloc) remaining -= current_alloc group['AMT_ALLOC_MONTH'] = allocations return group # 应用到每个部门 table = table.groupby('DEPT', group_keys=False).apply(calculate_monthly_alloc)
方法2:向量化计算(高性能,适合大数据量)
避免循环,用NumPy数组批量计算分配额,效率更高:
import pandas as pd import numpy as np table = table.sort_values(['DEPT', 'MONTH']) def calculate_alloc_vectorized(group): total_budget = group['AMT_TOTAL'].iloc[0] monthly_limit = group['LIMIT_MONTH'].iloc[0] num_months = len(group) # 计算需要多少个整月才能用完大部分预算 full_months = int(total_budget // monthly_limit) remaining_amount = total_budget % monthly_limit # 初始化分配数组,默认全为月度限额 allocations = np.full(num_months, monthly_limit) # 处理剩余预算和超出月份的情况 if full_months < num_months: if remaining_amount > 0: # 第full_months+1个月分配剩余预算,之后为0 allocations[full_months] = remaining_amount allocations[full_months+1:] = 0.0 else: # 刚好整除,第full_months个月是最后一笔,之后为0 allocations[full_months:] = 0.0 group['AMT_ALLOC_MONTH'] = allocations return group table = table.groupby('DEPT', group_keys=False).apply(calculate_alloc_vectorized)
关键说明
- 必须确保数据按
DEPT和月份排序,否则分配顺序会出错; - 假设每个部门的
AMT_TOTAL和LIMIT_MONTH是固定值(同一部门所有行的这两个值相同),如果你的数据中同一部门的这两个值有变化,需要调整函数逻辑(比如取每行的LIMIT_MONTH); - 两种方法都会覆盖原
AMT_ALLOC_MONTH列的NaN值,直接生成符合规则的分配额。
内容的提问来源于stack exchange,提问作者Zack Nguyen
相关产品推荐
相关产品推荐

