01|销量在撒谎:缺货那天,需求其实排着队

事故一时间线

先把那晚的事完整还原一遍,因为后面所有道理都从这张时间表里长出来:

时间发生了什么
21:47运营群截图:SKU-10086 库存 0、在途 0,客服话术改「补货中」
21:52计划同事甩报表:模型未来 7 天日均预测 520 件,「我们就是按 520 备的」
22:10拉出近 30 天销量:日均 512 件——模型没算错,它忠实地预测了它看到的东西
22:31有人问了一句:「这 30 天里,有几天是断货的?」
22:34答案:6 天。那 6 天销量分别是 0、0、0、210、0、0
22:40会议室安静了。真实日均需求不是 512,是 512×30 ÷ 24 ≈ 640
次日 09:00复盘结论:模型低估约 20%,备货跟着低估,断货是系统自己喂出来的

注意 22:10 到 22:34 之间的那四分钟:整个项目的认知被一句提问翻转了。问题不在模型,在数据的定义。

你看到的销量,是需求和库存里较小的那个

销量 = min(需求, 可供货量)。这句话值得抄在工位上。

  • 缺货那几天,销量是 0——但需求不是 0,顾客想买,只是没买到;

  • 大促限流那几个小时,销量被系统掐住,需求在排队;

  • 陈列位被砍、页面下架、区域停售,销量都会「凭空消失」。

    我画过一张对照图,把真实需求和系统里唯一能看到的销量放在一起:

df_01_demand_vs_sales.png

红色阴影就是被库存吃掉的部分。这段 60 天数据:真实需求合计 14024.0 件,观测销量 10682.5 件,被截断 3341.5 件——系统性低估 23.83% 。三段缺货(完全断货、只满足 35%、再次断货)在销量表里看起来只是「那几天生意不好」。

缺货螺旋:两轮推演给你看

为什么说这是「自我实现」的?用一个极简推演,真需求恒为每天 100 件:

发生了什么模型看到的周销量下周备货实际卖出
第 1 周一切正常700700700
第 2 周一切正常700700700
第 3 周供应商迟到 3 天(外部事故)400400
第 4 周模型学会「现在一周卖 400」400400400(需求 700,缺 300)
第 5 周模型确认「果然只卖 400」400400400
永久锁定在 400/周400400400

一次性的外部事故,经过「销量截断 → 模型学习 → 备货跟随 → 再次截断」的闭环,变成了永久性低估 43% 。没有任何人会察觉,因为报表上「预测准确率」一直很高——它准确地预测了自己造成的缺货。

这就是事故一的完整机理。模型不坏,坏的是闭环里没人校验「销量是否等于需求」。

销量还原:三种做法,各有适用场景

建模前的第一道工序,是把被截断的销量补回去。三种做法:

方法做法适用
速率法缺货前 k 天日均 × 缺货时长缺货短、需求平稳k 取太大会把趋势抹平
同期法上周同天销量 × 周环比系数有强周季节上周同天若也缺货,误差叠加
模型法用未缺货时段拟合的模型反推缺货期缺货长、有促销干扰模型本身有偏时会放大偏

手算(速率法) :缺货 3 天,缺货前 7 天日均 820 件 → 补 3 × 820 = 2460 件。

手算(同期法) :缺货的三天对应上周同三天销量 790 / 810 / 830,近四周周环比均值 1.02 → 还原为 790×1.02 = 806、810×1.02 = 826、830×1.02 = 847,合计 2479 件。

两种方法差 19 件(0.8%),可以接受;如果差超过 10%,说明需求在这几天有结构性变化,得查促销和流量。还原值要落库并打标(哪几天是还原的、用的哪种方法),否则三个月后没人说得清哪些数字是观测、哪些是估计。

「帮我预测一下销量」是一句无法执行的话

接过需求的人都知道这句话有多坑。可执行的预测任务必须钉死四个维度,下面是我开会时逐条问的清单:

对象与粒度

  1. 预测到 SKU 还是 SPU?颜色尺码算不算独立对象?

  2. 空间到全国、分仓、还是分门店?跨仓调拨算不算需求?

  3. 线上线下分开吗?直播渠道单独建模吗?

    时间窗与节奏

  4. 看多远:7 天补货、21 天采购、还是 13 周计划?预测窗口必须 ≥ 决策提前期(第 14 篇会算这笔账)。

  5. 日粒度还是周粒度?聚合会丢掉什么、换来什么?

    口径

  6. 预测需求还是销量?(读完本篇,答案永远是需求)

  7. 含退货吗?含赠品发出吗?含内部领用和调拨吗?

  8. 缺货期用还原值还是观测值?(还原值,且打标)

    责任与考核

  9. 这个预测给谁用?补货、排产、还是财务预算?三者容忍的误差方向完全不同。

  10. 考核用什么指标、按什么分层?(第 3、15 篇)

  11. 谁有权改预测?改了怎么留痕?(第 15 篇)

  12. 出错时归因的第一责任人是谁?

    问完这 12 个问题,项目成功率至少翻倍——因为它们把「预测」从一个模糊愿望变成了一个可验收的合同

    这里还有个绕不开的张力:决策发生在最细的粒度,信息量在最粗的粒度最充足。单仓单 SKU 明天卖多少鬼才知道,但全国品类月销稳得很。工业界解法:粗粒度预测准,再层级调和拆回去(第 13 篇)。

预测的产出是三样东西,不是一个数

初学者交差:「明天卖 523 件。」成熟的系统交一张预测卡片

字段给谁用
点预测 P50523报表、例会沟通
P10 / P25452 / 486清仓与停产判断
P75 / P90566 / 611大促备货、长提前期采购
理由分解基线 400 + 周末 60 + 促销 80 − 透支回补 17归因、干预、信任
基线对照Seasonal Naive = 508(本模型 +2.9%)上线门槛、兜底切换
置信说明近 28 天 P10~P90 覆盖率 81%(名义 80%)校准体检

第三行「理由」最容易被砍掉,也最致命:没有理由的预测,出错时无法归因,于是永远改不对;业务也不敢信一个说不出为什么的数字。

准不准,先看你亏得起哪种错

回到煎饼摊。老张的决策只取决于两个数字的比值:少摊一份亏 5 块(Cu),多摊一份亏 3 块(Co)。Cu > Co → 偏向多摊。换成当天必须销毁的鲜切花,结论立刻反转。

手算两个真实行业的对照,感受这个比值的力量:

行业售价成本季末残值Cu = 售价−成本Co = 成本−残值临界分位数 Cu÷(Cu+Co)该备到
生鲜叶菜1061450.444均值略低(z ≈ −0.14)
3C 配件100403060100.857均值 + 1.07σ

同一套预测系统,在叶菜上应该「宁可少备」,在 3C 配件上应该「宁可多备」——差别不在预测精度,在代价结构。这就是第 14 篇报童模型的全部输入,也是事故二那 240 万亏损的真正原因:没人做这张表。

预测误差本身不花钱,花钱的是「误差 × 代价结构」。 所以下次有人问「预测做到多少准确率才算好」,正确回答是反问:你们少备一件亏多少、多备一件亏多少?

读者问答:三个最常见的反驳

Q1:「缺货期很少,还原不还原影响不大吧?」 算一笔账:若某 SKU 一年缺货 12 天、日均 800 件,不还原就低估约 9600 件/年,占年销(约 29 万)的 3.3%。听起来小?这 3.3% 是系统性、单方向的,它会直接变成安全库存该加却没加的部分(第 14 篇:σ 低估 → SS 低估 → 缺货概率上升)。方向性偏差比随机误差贵得多。

Q2:「还原值是我们估的,拿估的数据训练不会引入新偏差吗?」 会,但两害相权:观测销量的偏差是向下截断(必然低估),还原值的偏差是估计误差(可双向、可度量、可迭代)。前者是系统性的坑,后者是可控的噪声。而且还原值打标后,你可以随时对比两种口径下模型的差异。

Q3:「需求根本观测不到,谈『真实需求』是不是伪命题?」 需求确实不可直接观测,但「被截断的部分」可以估计——缺货前的需求速率、排队数据、加购未支付、客服询单,都是证据链。工程上我们不追求「真值」,追求偏差方向已知且可修正:这就够了。

实操清单:本周就能做的六件事

  1. 拉出近 90 天「库存 = 0 或售罄率 > 95%」的天数清单,按 SKU 排序——你会第一次看见截断的规模。
  2. 对 Top 20 缺货 SKU 用速率法做还原,对比还原前后的日均需求差,把差值换算成年化金额。
  3. 在事实表加三列:stockout_flag、stockout_hours、demand_qty(还原值),并写还原方法的单元测试。
  4. 把「预测需求还是销量」写进需求文档第一行,让业务签字。
  5. 为每个 SKU 建 Cu/Co 卡片(售价、成本、残值、缺货流失估计),算出临界分位数。
  6. 在周报里加一列「还原口径 vs 观测口径的预测差异」,让团队对截断保持痛感。

带走三句话:销量 = min(需求, 可供货量),建模前先还原并打标;缺货螺旋会把一次性事故变成永久低估;Cu÷(Cu+Co) 决定你该备到哪个分位数,与精度无关。

下一篇:数据洗干净了,接下来看懂它的形状——把一条乱糟糟的曲线拆成四块积木,我会证明为什么「中心化移动平均」能恰好抹掉季节。