跳到主要内容

三次指数平滑

一、直观理解:水平 + 趋势 + 季节三套状态一起更新​

三次指数平滑即 Holt-Winters 方法,在 Holt 的水平上加入季节分量 sts_t。以加性季节为例:

lt=α(yt−st−m)+(1−α)(lt−1+bt−1)bt=β(lt−lt−1)+(1−β)bt−1st=γ(yt−lt)+(1−γ)st−my^t+h∣t=lt+hbt+st+h−m⌊(h−1)/m⌋\begin{aligned} l_t&=\alpha(y_t-s_{t-m})+(1-\alpha)(l_{t-1}+b_{t-1})\\ b_t&=\beta(l_t-l_{t-1})+(1-\beta)b_{t-1}\\ s_t&=\gamma(y_t-l_t)+(1-\gamma)s_{t-m}\\ \hat y_{t+h|t}&=l_t+hb_t+s_{t+h-m\lfloor(h-1)/m\rfloor} \end{aligned}

其中 mm 为周期(月数据 12,季数据 4)。若季节幅度随水平变大,用乘性季节:

y^t+h∣t=(lt+hbt) st+h−m(⋅)\hat y_{t+h|t}=(l_t+hb_t)\,s_{t+h-m(\cdot)}

可以把它想成:先把“今年春节/暑假”的固定形态记住,再叠到更新后的趋势上。

二、适用场景与优缺点​

类型说明
适用场景明显季节 + 可选趋势;周期长度已知;需要快速可解释的季节预测;与 SARIMA/Prophet 对照。
核心优点三组件直观;计算轻;对业务沟通友好;常成为强基线。
局限与缺点季节模式缓慢变化尚可,突然变形则滞后;多周期(周+年)吃力;参数三维网格有过拟合风险;弱于含多个日历事件的精细建模。

三、核心原理​

1. 加性 vs 乘性​

  • 加性:季节波动绝对幅度大致恒定;
  • 乘性:旺季“按比例”放大。

画图看淡旺季落差是否随趋势变大,或比较两者验证误差。

2. 初始化​

  • 水平/趋势:用前两个周期的均值与差分;
  • 季节:第一个周期内 yt−yˉy_t-\bar y(加性)或 yt/yˉy_t/\bar y(乘性),并做零和/均值 1 归一。

3. 与 SARIMA 的分工​

Holt-Winters 是确定性状态平滑;SARIMA 是随机过程。很多题目两者误差接近,应同时报告;若残差仍强相关,可偏向 SARIMA 或对 HW 残差再建模。

四、参数与验证​

网格搜索 α,β,γ\alpha,\beta,\gamma(及阻尼 ϕ\phi),用训练期末之前的验证段或一步 SSE。周期 mm 必须来自业务,不可乱试。

基线强制包括:

  • 季节朴素:y^t+h=yt+h−m\hat y_{t+h}=y_{t+h-m};
  • Holt(无季节);
  • 可选 SARIMA。

若打不过季节朴素,说明趋势/季节更新没有带来价值。

五、MATLAB 示例​

%% Holt-Winters 加性季节(手写核心)
rng(12);
m = 12; n = 144;
t = (1:n)';
y = (30 + 0.08*t) + 6*sin(2*pi*t/m) + randn(n,1);

T0 = 120;
yTrain = y(1:T0); yTest = y(T0+1:end);

% 初始化
l = mean(yTrain(1:m));
b = (mean(yTrain(m+1:2*m)) - mean(yTrain(1:m)))/m;
s = zeros(m,1);
s(1:m) = yTrain(1:m) - l;
s = s - mean(s); % 零和

% 网格
alphas = 0.2:0.2:0.8;
betas = 0.05:0.1:0.35;
gammas = 0.2:0.2:0.8;
best = struct("sse",Inf);
for a = alphas
for be = betas
for g = gammas
ll = l; bb = b; ss = s; sse = 0;
for i = 1:numel(yTrain)
if i-m >= 1
yhat = ll + bb + ss(mod(i-1,m)+1);
if i > m % 跳过最初不稳定期
sse = sse + (yTrain(i)-yhat)^2;
end
llNew = a*(yTrain(i)-ss(mod(i-1,m)+1)) + (1-a)*(ll+bb);
bb = be*(llNew-ll) + (1-be)*bb;
ss(mod(i-1,m)+1) = g*(yTrain(i)-llNew) + (1-g)*ss(mod(i-1,m)+1);
ll = llNew;
else
% 前 m 点主要用于填季节,略
llNew = a*(yTrain(i)-ss(mod(i-1,m)+1)) + (1-a)*(ll+bb);
bb = be*(llNew-ll) + (1-be)*bb;
ss(mod(i-1,m)+1) = g*(yTrain(i)-llNew) + (1-g)*ss(mod(i-1,m)+1);
ll = llNew;
end
end
if sse < best.sse
best = struct("sse",sse,"a",a,"be",be,"g",g,"ll",ll,"bb",bb,"ss",ss);
end
end
end
end
fprintf("alpha=%.2f beta=%.2f gamma=%.2f\n", best.a, best.be, best.g);

% 预测
h = numel(yTest);
yf = zeros(h,1);
for k = 1:h
yf(k) = best.ll + k*best.bb + best.ss(mod(T0+k-1,m)+1);
end
rmse = sqrt(mean((yTest-yf).^2));

% 季节朴素
ysn = yTrain(end-m+1:end);
ysn = repmat(ysn, ceil(h/m),1); ysn = ysn(1:h);
rmse_sn = sqrt(mean((yTest-ysn).^2));
fprintf("测试 RMSE HW=%.3f, 季节朴素=%.3f\n", rmse, rmse_sn);

figure;
plot(1:T0,yTrain,"k"); hold on;
plot(T0+1:n,yTest,"k");
plot(T0+1:n,yf,"r","LineWidth",1.2);
plot(T0+1:n,ysn,"b--");
xline(T0,"k--");
legend("训练","测试","Holt-Winters","季节朴素");
title("三次指数平滑");

若使用较新 MATLAB 版本,也可查是否提供 ets 或相关工具箱函数;手写版本便于论文展示公式与参数。

六、如何解释结果​

报告:

  1. 周期 mm 与加性/乘性选择理由;
  2. α,β,γ\alpha,\beta,\gamma 及初始化;
  3. 最终季节因子图(一个周期的形态);
  4. 水平与趋势期末值;
  5. 测试误差对比季节朴素、Holt、SARIMA;
  6. 残差是否仍有季节峰;
  7. 节假日是否需额外哑变量(HW 本身不专门建模移动节日)。

七、常见误区​

1. 周期设错​

把周数据的年季节当成 m=7m=7 只会建模星期效应,抓不住年周期。

2. 不比季节朴素​

这是季节题的必比基线。

3. 乘性用于含非正值序列​

y≤0y\le 0 时乘性季节不成立。

4. 网格太粗或只调一个参数​

三参数互相耦合,至少做粗网格 + 局部加密。

5. 长期预测仍沿用强趋势​

可加阻尼趋势,或缩短决策视野。

八、小结​

三次指数平滑的核心是:

在指数平滑框架内同时更新水平、趋势与季节,使预测既顺势又保持周期形态。

它是季节性业务序列的第一强基线,实现简单、解释清楚。论文中写清加性/乘性、周期、参数选择,并用训练期外误差证明它相对季节朴素的改进(或诚实地承认没有改进)。不要只看 R2R^2 或样本内贴合曲线。