02|把销量曲线拆成四块积木:附一个「为什么移动平均能抹掉季节」的证明

「这团乱麻也能预测?」

第一次把某 SKU 两年日销投到会议室大屏时,老板的反应是:「这团乱麻也能预测?」

我的回答是:能。因为它不是乱麻,是四块积木叠在一起——叠着看是乱麻,拆开看每一块都老实得很。那天我在白板上画了四条线,会议从「要不要做预测」变成了「预测怎么做」。这篇把白板重现一遍。

一条曲线 = 趋势 + 季节 + 残差

y(t)=T(t)+S(t)+R(t)y(t) = T(t) + S(t) + R(t)
  • T 趋势:这门生意整体在涨还是在跌。老板看的「大盘」就是它。

  • S 季节:固定周期、固定形状的重复波动——周末高、夏天高、月初高。它是日历写在销量上的签名。

  • R 残差:解释不掉的部分,真正的不确定性

    拆完之后的世界观会变:规律可以外推,残差只能靠库存去扛。 预测方法的全部工作就是把 T 和 S 解释掉;剩下的 R,交给安全库存和分位数(第 12、14 篇)。所以一个预测系统好不好,本质上看它「解释掉了多少、剩下多少」。

df_02_components.png

上图是一段 48 个月数据的分解。脚本算出的 12 个加法季节因子(单位:件):

123456789101112
S−359.7−413.4−210.3−91.3+28.6+176.3+277.5+148.8+20.5−92.8+131.6+384.3

读法:2 月比趋势水平少卖 413 件,12 月多卖 384 件。这就是这个品类的「年历」——拿到它,你甚至不需要模型就能做季度计划:明年 Q 的预测 = 明年 Q 的趋势估计 + 对应因子。

两个体检性质顺手记:加法因子之和必须为 0(本例 −0.0000,否则日历自带偏见);残差标准差 σ_R = 22.19——这个数字会一路走到第 14 篇的安全库存公式里。

还有个反直觉细节:这段数据注入的噪声标准差是 45,但分解后残差只有 22.19。因为移动平均在估趋势时吸收了一部分噪声。结论:残差 ≠ 原始噪声,它是「模型解释完之后剩下的」不确定性——模型越好,残差越小,库存越省。这就是预测项目省钱的第一条路径。

证明:中心化移动平均为什么恰好抹掉季节

很多人把「移动平均去季节」当黑箱。其实它是个三行的代数事实。

设加法模型 y(t) = T(t) + S(t) + R(t),季节因子已归一化,即一个完整周期内因子之和为 0:

i=0m1S(t+i)=0\sum_{i=0}^{m-1} S(t+i) = 0

先验证这个前提在我们手算的季度数据上成立:−51.328 + 10.672 + 68.672 + (−28.016) = 0.000。✓

现在取一个恰好覆盖 m 个不同季节位置的窗口求平均:

1miy(t+i)=1miT(t+i)+1miS(t+i)=0+1miR(t+i)\frac{1}{m}\sum_{i} y(t+i) = \frac{1}{m}\sum_{i} T(t+i) + \underbrace{\frac{1}{m}\sum_{i} S(t+i)}_{=0} + \frac{1}{m}\sum_{i} R(t+i)

第二项恒为 0(前提);第三项是噪声平均,窗口越长越接近 0;第一项在窗口内若 T 近似线性,就等于窗口中心处的 T。于是平均值 ≈ 中心处的趋势。 季节就这样被「平均没了」——不是魔法,是归一化的直接推论。

那为什么偶数 m 要「两端各取半权」? 因为偶数窗口(如 m=4 取 t..t+3)的中心落在两期之间,覆盖的季节位置是 {0,1,2,3} 但中心不对齐任何一期。给两端各半权后,窗口变成「半 + 全 + 全 + 全 + 半」,覆盖的季节位置集合仍是每个位置恰好一次(半权的两端是同一个季节位置的前后周期,合起来算一次),和仍为 0,且中心正好落在整数期上。

手算验证(第 t=3 期,季度数据):

T(3)=0.5×120+180+240+150+0.5×1324=6964=174.000T(3) = \frac{0.5 \times 120 + 180 + 240 + 150 + 0.5 \times 132}{4} = \frac{696}{4} = 174.000

人话:半个 Q1 + 完整一年 + 半个 Q1 = 恰好一个整年的季节签名互相抵消。

加法还是乘法:给「喇叭口」一个量化判据

  • 加法:季节波动的绝对量固定。水平翻倍,周末还是多卖 50 件。
  • 乘法:季节波动是倍数。水平翻倍,周末多卖的量也翻倍。
y(t)=T(t)S(t)R(t)y(t) = T(t) \cdot S(t) \cdot R(t)

df_03_additive_vs_multiplicative.png

肉眼判据是「看喇叭口」,但评审会上肉眼会吵架。量化判据用相对振幅 = (窗口内 max − min) ÷ 窗口内均值,比较水平高低两段:

数据形态低水平段(均值 500)高水平段(均值 1000)相对振幅变化判定
振幅 50 → 520.100.052减半加法
振幅 50 → 1000.100.10不变乘法

判据一句话:相对振幅随水平下降 → 加法;相对振幅恒定 → 乘法。 实务经验:电商零售绝大多数 SKU 是乘法型(促销与季节本质是倍数效应,打五折就是 ×2);物流成本、人力排班更接近加法型。选错的典型症状:高水位时区间该宽不宽,低水位时该窄不窄。

季节指数完整手算:三步 + 一步验证

用某饮料 SKU 的 12 个季度销量(万件):三年依次 120/180/240/150、132/196/260/164、145/214/283/179。

第 1 步:中心化移动平均估趋势(公式见上),可得位置全部算出:

t345678910
T174.000177.500182.000186.250189.625193.500198.625203.375
y−T+66.00−27.50−50.00+9.75+70.38−29.50−53.62+10.62
y÷T1.37930.84510.72531.05231.37110.84750.73001.0522

第 2 步:同季放一起求平均。 三年的 Q3 摆在一起,季节显形:加法平均 +68.188,乘法平均 1.3752。

第 3 步:归一化。 加法各减去均值 −0.484;乘法各除以均值 1.0004:

季度Q1Q2Q3Q4
加法因子−51.328+10.672+68.672−28.016
乘法因子0.72741.05191.37470.8460

第 4 步(多数人漏掉):验证。 用 T + 加法因子还原拟合值,看残差:

t345678910
拟合 T+S242.672149.484130.672196.922258.297165.484147.297214.047
残差 y−拟合−2.672+0.516+1.328−0.922+1.703−1.484−2.297−0.047

残差平方和 = 20.400,除以 8 = 2.550,RMSE = 1.597 万件——相对 200 万量级的季度销量,分解解释了 99% 以上的波动。这一步的意义:它告诉你「积木拆干净了」,剩下的 1.6 才是需要扛的不确定性。

残差诊断:拆完别急着庆祝

回头看残差序列,三个检查:

  1. 还有周期吗? 把残差按星期/月份分组求均值,若某组显著非零 → 季节没建好(常见于季节形状在漂移,第 7 篇 γ 的作用)。

  2. 均值非零吗? 残差均值 = −Bias 的雏形 → 有系统性方向错误(第 3 篇)。

  3. 方差在变大吗? 分段比较残差标准差(如前半年 vs 后半年)。变大 → 该换乘法模型,或先取对数把乘法变加法。

    三条都干净,才轮到模型出场炫耀。

预告一类敌人:四块积木全失效的序列

如果序列长这样:0, 0, 4, 0, 6, 0, 0, 0, 5 … 大部分时间是 0,偶尔来一单。趋势和季节都无从谈起,移动平均会被 0 一路拖低。

给它两个体检指标:

  • ADI(平均需求间隔) = 总期数 ÷ 有需求的期数。本例 9 ÷ 3 = 3.0

  • CV²(非零需求量的变异系数平方) = 方差 ÷ 均值²。非零值 [4, 6, 5]:均值 5,方差 (1+1+0)÷3 = 0.667,CV² = 0.667 ÷ 25 = 0.027

    按 Syntetos-Boylan 分类(ADI > 1.32 且 CV² ≤ 0.49 → 间歇象限),它正是长尾 SKU 的主流形态。专治方法 Croston/TSB,第 13 篇手算给你看。

读者问答

Q1:季节因子会过时吗? 会。季节形状随品类结构、客群、渠道变化而漂移。监控方法:每季度重算一次因子,与在用因子对比;若单季偏差超过残差 σ 的 2 倍,触发更新。HW 里的 γ 就是「在线版」的这个更新(第 7 篇)。

Q2:只有不到一个完整周期的数据(如新品 5 个月),能分解吗? 不能可靠分解。此时借品类季节因子 × 自身水平(层级借用,第 13 篇),或直接用周季节(周期短、样本够)先顶着。

Q3:趋势和季节会互相污染吗? 会,尤其在周期与窗口不对齐时。所以第 1 步必须用「恰好覆盖整周期」的中心化窗口;若用错窗口(如 m=12 却取 10 期平均),季节残留会渗进趋势,趋势再渗进预测——误差变得既有方向又有周期,最难排查。

实操清单

  1. 对 Top 50 SKU 画「原始 + 12 期中心化 MA」双线图,肉眼看喇叭口定加法/乘法。
  2. 用相对振幅判据(高低两段对比)复核肉眼结论,不一致的 SKU 单独标记。
  3. 手算或脚本算季节因子后,必做第 4 步验证:还原拟合、算残差 RMSE,并存档。
  4. 残差三检查做成月度自动报告:周期残留、均值偏移、方差漂移。
  5. 给每个 SKU 记录 ADI 与 CV²,把间歇象限的 SKU 分流到第 13 篇的方法,别让平滑模型硬啃。

带走三句话:曲线 = 趋势 + 季节 + 残差,规律可外推、残差只能扛;中心化 MA 抹掉季节靠的是「整周期因子和为 0」这条代数事实,偶数窗口需半权对齐;加法乘法用相对振幅是否恒定来判,别靠肉眼吵架。

下一篇:分解做完,该定义「准」了——六个误差指标、一场 MAE 相同却命运不同的实验、和一份能直接抄的一页纸误差报告。