三次指数平滑
一、直观理解:水平 + 趋势 + 季节三套状态一起更新
三次指数平滑即 Holt-Winters 方法,在 Holt 的水平上加入季节分量 。以加性季节为例:
其中 为周期(月数据 12,季数据 4)。若季节幅度随水平变大,用乘性季节:
可以把它想成:先把“今年春节/暑假”的固定形态记住,再叠到更新后的趋势上。
二、适用场景与优缺点
| 类型 | 说明 |
|---|---|
| 适用场景 | 明显季节 + 可选趋势;周期长度已知;需要快速可解释的季节预测;与 SARIMA/Prophet 对照。 |
| 核心优点 | 三组件直观;计算轻;对业务沟通友好;常成为强基线。 |
| 局限与缺点 | 季节模式缓慢变化尚可,突然变形则滞后;多周期(周+年)吃力;参数三维网格有过拟合风险;弱于含多个日历事件的精细建模。 |
三、核心原理
1. 加性 vs 乘性
- 加性:季节波动绝对幅度大致恒定;
- 乘性:旺季“按比例”放大。
画图看淡旺季落差是否随趋势变大,或比较两者验证误差。
2. 初始化
- 水平/趋势:用前两个周期的均值与差分;
- 季节:第一个周期内 (加性)或 (乘性),并做零和/均值 1 归一。
3. 与 SARIMA 的分工
Holt-Winters 是确定性状态平滑;SARIMA 是随机过程。很多题目两者误差接近,应同时报告;若残差仍强相关,可偏向 SARIMA 或对 HW 残差再建模。
四、参数与验证
网格搜索 (及阻尼 ),用训练期末之前的验证段或一步 SSE。周期 必须来自业务,不可乱试。
基线强制包括:
- 季节朴素:;
- 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 或相关工具箱函数;手写版本便于论文展示公式与参数。
六、如何解释结果
报告:
- 周期 与加性/乘性选择理由;
- 及初始化;
- 最终季节因子图(一个周期的形态);
- 水平与趋势期末值;
- 测试误差对比季节朴素、Holt、SARIMA;
- 残差是否仍有季节峰;
- 节假日是否需额外哑变量(HW 本身不专门建模移动节日)。
七、常见误区
1. 周期设错
把周数据的年季节当成 只会建模星期效应,抓不住年周期。
2. 不比季节朴素
这是季节题的必比基线。
3. 乘性用于含非正值序列
时乘性季节不成立。
4. 网格太粗或只调一个参数
三参数互相耦合,至少做粗网格 + 局部加密。
5. 长期预测仍沿用强趋势
可加阻尼趋势,或缩短决策视野。
八、小结
三次指数平滑的核心是:
在指数平滑框架内同时更新水平、趋势与季节,使预测既顺势又保持周期形态。
它是季节性业务序列的第一强基线,实现简单、解释清楚。论文中写清加性/乘性、周期、参数选择,并用训练期外误差证明它相对季节朴素的改进(或诚实地承认没有改进)。不要只看 或样本内贴合曲线。