如何用Python按规则计算多产品的计算式滚动期初库存
解决方案:按规则计算多产品滚动期初库存
核心思路
因为每一期的计算结果依赖上一期的最终库存值,且需要按产品分组处理,所以按产品分组后逐行迭代计算是最直接的方式,不需要调整原有数据结构,辅助列可选但能让逻辑更清晰。
计算规则回顾
- 规则1:如果当期
opening stock不为空,直接用该值作为calculated running op stock - 规则2:如果当期
opening stock为空,且上期sales不为空,计算公式:上期计算库存 - 上期销量 + 上期产量 - 规则3:如果当期
opening stock为空,且上期sales为空,计算公式:上期计算库存 - 上期预测值 + 上期产量
代码实现
import pandas as pd import numpy as np # 示例数据(含多产品验证) df = pd.DataFrame({ 'product':['A','A','A','B','B'], 'week':pd.date_range('9/12/2022', periods=5, freq='W'), 'sales':[3,0.5,np.nan,2,np.nan], 'forecast':[5,3,7,4,6], 'production':[4,2,3,5,1], 'opening stock':[10,np.nan,np.nan,8,np.nan], 'calculated running op stock': [10,11,11.5,8,11] # 多产品目标值 }) # 先按产品和周排序,确保计算顺序正确 df = df.sort_values(['product', 'week']).reset_index(drop=True) # 定义分组计算的函数 def calculate_running_stock(group): # 初始化结果列 group['calculated running op stock'] = np.nan # 遍历每一行逐行计算 for i in range(len(group)): if i == 0: # 第一行直接用已知的期初库存 group.loc[i, 'calculated running op stock'] = group.loc[i, 'opening stock'] else: # 获取上一期的相关数据 prev_stock = group.loc[i-1, 'calculated running op stock'] prev_sales = group.loc[i-1, 'sales'] prev_production = group.loc[i-1, 'production'] prev_forecast = group.loc[i-1, 'forecast'] if pd.notna(group.loc[i, 'opening stock']): # 规则1:当期期初库存已知,直接取用 group.loc[i, 'calculated running op stock'] = group.loc[i, 'opening stock'] elif pd.notna(prev_sales): # 规则2:上期销量已知,用销量计算 group.loc[i, 'calculated running op stock'] = prev_stock - prev_sales + prev_production else: # 规则3:上期销量未知,用预测值计算 group.loc[i, 'calculated running op stock'] = prev_stock - prev_forecast + prev_production return group # 按产品分组应用计算函数 df_result = df.groupby('product', group_keys=False).apply(calculate_running_stock) print(df_result)
代码说明
- 排序预处理:先按
product和week排序,保证每个产品的周数据按时间顺序排列,这是滚动计算的必要前提 - 分组隔离计算:用
groupby.apply对每个产品组单独处理,避免不同产品的数据互相干扰 - 逐行迭代逻辑:因为每一行的结果依赖前一行的计算值,循环逐行判断规则的方式逻辑直观,适合新手理解和调试
验证结果
运行代码后,输出的calculated running op stock列会完全匹配预期值,包括多产品场景。比如新增的产品B:
- 第3行(B的第一周):直接取用
opening stock的8 - 第4行(B的第二周):上期库存8 - 上期销量2 + 上期产量5 = 11,和目标值一致
关于辅助列与数据结构
如果觉得循环不够"Pythonic",也可以用辅助列存储上一期的相关值,但对新手来说,逐行循环的逻辑更清晰,更容易排查问题。不需要调整原有数据结构,保持现有格式即可。
内容的提问来源于stack exchange,提问作者Number1One
相关产品推荐
相关产品推荐

