需求预测到库存决策的完整流水线——安全库存 = z × σ × √lead_time,√ 来自方差线性累积¶
核心操作¶
三步流水线:交易数据 → 日需求 → 库存策略 → 蒙特卡洛模拟验证。
步骤 1: 零填充缺失天数(最易被跳过的步骤)
# 交易数据聚合后,创建完整日期范围并填充 0
daily = daily.reindex(
pd.date_range(start=daily.index.min(), end=daily.index.max(), freq='D'),
fill_value=0
)
为什么关键:不填充意味着「0 销量的天数不进入训练数据」→ 需求预测系统性偏高 → 安全库存不足 → 缺货。
步骤 2: 安全库存公式的核心——√lead_time
mu_lt = mu_daily * lead_time # 提前期内期望需求
sigma_lt = sigma_daily * np.sqrt(lead_time) # 提前期内需求不确定性
safety_stock = norm.ppf(service_level) * sigma_lt
rop = mu_lt + safety_stock # 重订货点
为什么是 √lead_time? 方差线性累积:Var(提前期需求) = Var(日需求) × lead_time,所以 σ(提前期需求) = σ_daily × √lead_time。直观理解:提前期翻倍,不确定性只增加 41%(√2 ≈ 1.41),因为每天的需求波动之间部分抵消。
步骤 3: 蒙特卡洛验证(策略上线前必须做)
不直接信任公式输出 → 用模拟生成 10,000 条可能的日需求路径,在每条路径上运行库存策略,计算缺货率、平均库存和未满足需求。公式给出的是「理论服务水平」,模拟给出的是「这个策略在实际需求波动下的真实表现」。
💡 关键教训¶
零填充是最简单的操作、最常被遗忘、后果最严重。零售数据的 0 值天数是信号(「这个单品今天没人买」),不是缺失值。用 pandas 的 reindex + fill_value=0——一行代码,但跳过这一行的代价是安全库存系统性地少估算 15-30%,因为平均需求被高估。
服务水平的隐藏成本:从 95% 到 99% 的服务水平,安全库存不是增加 4%——是增加约 30%(因为 norm.ppf(0.99)/norm.ppf(0.95) ≈ 2.33/1.64 ≈ 1.42 倍)。服务水平每提高 1 个百分点,库存成本的边际增速是递增的——这是为什么「零缺货」目标在经济上不可行。
单品级预测的必要性:按品类聚合预测(「咖啡类别日需求 200 杯」)无法驱动单品级库存决策(「美式 vs 拿铁的日需求分别多少?」)。聚合 → 单品拆分需要分配规则,而这个分配规则本身就是一个未建模的假设。