6.4 平滑:移动平均、指数平滑、Holt-Winters


6.4 平滑:移动平均、指数平滑、Holt-Winters

本节摘要:指数平滑族是 ARIMA 之外另一类主流时序模型。本节介绍 SES(简单指数平滑)、Holt(带趋势)、Holt-Winters(带趋势 + 季节)三套方法,并用一段带趋势和周季节性的合成数据演示完整拟合。

先看目标

阅读完本节,你应当能够:

  1. 写出 SES、Holt、Holt-Winters 三种方法的递推公式与适用场景。
  2. 用 statsmodels 的 ExponentialSmoothing 拟合数据,并解释 trend / seasonal / seasonal_periods 参数。
  3. 在 ARIMA 与指数平滑之间做工程选择。

本节介绍 ARIMA 之外的另一类主流——指数平滑族。读完后你掌握三参数 (α、β、γ) 的工程含义,以及"加法 vs 乘法季节"的选型决策。

一、SES:简单指数平滑

SES(Simple Exponential Smoothing)只建模水平项,假设序列没有趋势也没有季节性。递推公式:

ℓ(t) = α y(t) + (1 - α) ℓ(t-1) ŷ(t+h) = ℓ(t)

α ∈ (0, 1) 是平滑系数,控制"对最新观测的权重"。

  • α 接近 1:对新数据敏感,预测紧跟。
  • α 接近 0:预测平滑、滞后。
from statsmodels.tsa.holtwinters import SimpleExpSmoothing, ExponentialSmoothing ses = SimpleExpSmoothing(s, initialization_method="estimated").fit(smoothing_level=0.3) forecast = ses.forecast(12)

SES 适用:没有趋势、没有季节性、只有随机波动的序列(如某些金融资产价格、传感器噪声)。

二、Holt:带趋势的双参数指数平滑

Holt 在 SES 基础上加了一个趋势项 b(t)

ℓ(t) = α y(t) + (1 - α) (ℓ(t-1) + b(t-1)) b(t) = β (ℓ(t) - ℓ(t-1)) + (1 - β) b(t-1) ŷ(t+h) = ℓ(t) + h b(t)

β 是趋势平滑系数。trend="add" 表示加法趋势;trend="mul" 表示乘法趋势(趋势随水平放大)。

holt = ExponentialSmoothing(s, trend="add").fit()

Holt 适用:有趋势但无季节性的序列(如持续增长的销售额、用户数)。

⚠️ 常见坑:Holt 默认会"无限外推趋势"——预测 10 年后销量会按当前斜率一直涨。实战中要给趋势一个上限,或者用 damped_trend=True 让趋势逐渐衰减到 0。

holt_damped = ExponentialSmoothing(s, trend="add", damped_trend=True).fit() # φ 控制趋势衰减速度,φ=0.98 是常用经验值

三、Holt-Winters:趋势 + 季节

Holt-Winters 在 Holt 基础上再加季节项 s(t),有三组参数 (α, β, γ) 分别控制水平、趋势、季节的平滑。

# 加法季节 ℓ(t) = α (y(t) - s(t-m)) + (1 - α) (ℓ(t-1) + b(t-1)) b(t) = β (ℓ(t) - ℓ(t-1)) + (1 - β) b(t-1) s(t) = γ (y(t) - ℓ(t-1) - b(t-1)) + (1 - γ) s(t-m) ŷ(t+h) = ℓ(t) + h b(t) + s(t+h-m)

m 是季节周期(7 = 周、12 = 月、24 = 小时数据中的日季节)。

hw = ExponentialSmoothing( s, trend="add", seasonal="add", seasonal_periods=12 ).fit()

Holt-Winters 适用:同时有趋势和季节性的序列(如零售月度销量——上升 + 12 月高峰)。

四、加法 vs 乘法季节

参考 2.5 节,季节性幅度随水平变化时用乘法:

hw_mul = ExponentialSmoothing( s, trend="add", seasonal="mul", seasonal_periods=12 ).fit()

实战经验:销售类数据用乘法季节;物理量类数据用加法季节。

五、一个完整案例:航空乘客数据

from statsmodels.datasets import airline data = airline.load_pandas().data data["Month"] = pd.to_datetime(data["Month"]) data = data.set_index("Month") y = data["AirPassengers"] # Holt-Winters 加法趋势 + 乘法季节(航空数据经典配置) hw = ExponentialSmoothing( y, trend="add", seasonal="mul", seasonal_periods=12, initialization_method="estimated" ).fit() # 预测未来 24 个月 forecast = hw.forecast(24) print(hw.summary().tables[1]) # 拟合参数 α、β、γ

输出参数表里会有 smoothing_level (α)、smoothing_trend (β)、smoothing_seasonal (γ) 三个值。每个都在 0–1 之间,接近 0 表示对应成分稳定,接近 1 表示新数据贡献大

六、ARIMA vs 指数平滑

维度 ARIMA 指数平滑
推导方式 统计(自相关、平稳性) 启发式(递推、误差反馈)
季节性 显式季节项 显式季节项
趋势 隐式(通过差分) 显式(独立参数)
阻尼趋势 需手动 damped_trend=True
预测区间 严格推导 经验区间
数据需求 至少 50 个观测 至少 2 个完整周期

工程选择:

  • 数据有明确季节性 + 解释性优先 → 指数平滑(Holt-Winters 参数可解释)。
  • 数据需要外生变量(促销活动、宏观经济)→ ARIMAX。
  • 数据有多重季节性 → Prophet 或 NeuralForecast。
  • 数据稀缺(< 30 个观测)→ 朴素季节性 / SES。

七、一个工程陷阱:季节周期选错

如果数据是工作日数据,"季节周期"是 5 而不是 7。如果错选 7,模型会试图学"7 天后的同一天",但工作日没有 7 天周期——预测会显著偏差。

# 错误:业务上只有工作日,但选了 m=7 hw_wrong = ExponentialSmoothing(workday_sales, seasonal="add", seasonal_periods=7).fit() # 正确:m=5 匹配业务周期 hw_right = ExponentialSmoothing(workday_sales, seasonal="add", seasonal_periods=5).fit()

本节要点回顾

  • SES:无趋势无季节的简单平滑。
  • Holt:加趋势(可阻尼)。damped_trend=True 让趋势不无限外推。
  • Holt-Winters:加趋势 + 季节。三参数 (α, β, γ) 控制平滑强度。
  • 加法 vs 乘法季节:销售类用乘法、物理量用加法。
  • ARIMA vs 指数平滑:解释性优先选指数平滑;外生变量选 ARIMAX;数据稀缺选朴素基线。
  • 常见坑:季节周期选错(工作日 m=5 而非 7)、趋势不阻尼、α/β/γ 随意调。
  • 下一节线索:6.5 介绍 ARIMA / SARIMA 模型族,及完整选型决策表。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U