3. 指数平滑法

指数平滑法(Exponential Smoothing)是供应链需求预测中最常用的时间序列方法之一。其核心思想是:越近期的观测值包含越多的预测信息,因此赋予更高的权重;权重随时间呈指数衰减。本章从一次指数平滑出发,逐步深入到能处理趋势和季节性的Holt-Winters模型,并给出完整的Python实现与调参指南。

3.1 一次指数平滑(Simple Exponential Smoothing, SES)

一次指数平滑适用于无趋势、无季节性的平稳时间序列。其预测公式为:

预测值 F_{t+1} = α * Y_t + (1 - α) * F_t

其中:
- Y_t:t 时刻的实际观测值
- F_t:t 时刻的预测值(即对 t-1 时刻的预测)
- α:平滑系数(0 ≤ α ≤ 1),控制新旧信息的权重

关键特性:

  • α 越接近 1,模型越“敏感”,对近期变化反应快,但易受随机波动影响。
  • α 越接近 0,模型越“平滑”,历史信息保留多,但滞后性明显。
  • 初始值 F_1 通常取 Y_1 或前几期的平均值。
供应链应用场景: 用于预测日销量稳定的快消品、标准件库存消耗。当产品处于成熟期且无促销扰动时,SES 是快速基线预测的首选。

3.2 二次指数平滑(Holt's Linear Trend Model)

当序列存在趋势(持续上升或下降)时,一次指数平滑会产生系统性滞后。Holt 模型引入趋势分量,同时平滑水平和趋势:

水平方程:L_t = α * Y_t + (1 - α) * (L_{t-1} + T_{t-1})
趋势方程:T_t = β * (L_t - L_{t-1}) + (1 - β) * T_{t-1}
预测方程:F_{t+m} = L_t + m * T_t

其中:
- L_t:t 时刻的平滑水平
- T_t:t 时刻的平滑趋势
- α:水平平滑系数
- β:趋势平滑系数(0 ≤ β ≤ 1)
- m:预测步长

参数含义对比:

参数 取值范围 大值效果 小值效果
α(水平) [0, 1] 快速跟踪水平变化 平滑水平波动
β(趋势) [0, 1] 快速响应趋势变化 趋势更稳定
注意: 当 β=0 时,趋势变为常数,模型退化为一次指数平滑加固定趋势。实际应用中,β 通常设为较小值(0.1~0.3),避免趋势过度反应。

3.3 三次指数平滑(Holt-Winters Model)

当序列同时存在趋势和季节性时,Holt-Winters 模型在 Holt 模型基础上增加季节分量。根据季节效应与趋势的关系,分为加法模型和乘法模型:

加法模型(季节幅度恒定):
水平:L_t = α * (Y_t - S_{t-p}) + (1-α) * (L_{t-1} + T_{t-1})
趋势:T_t = β * (L_t - L_{t-1}) + (1-β) * T_{t-1}
季节:S_t = γ * (Y_t - L_t) + (1-γ) * S_{t-p}
预测:F_{t+m} = L_t + m*T_t + S_{t+m-p}

乘法模型(季节幅度随水平变化):
水平:L_t = α * (Y_t / S_{t-p}) + (1-α) * (L_{t-1} + T_{t-1})
趋势:T_t = β * (L_t - L_{t-1}) + (1-β) * T_{t-1}
季节:S_t = γ * (Y_t / L_t) + (1-γ) * S_{t-p}
预测:F_{t+m} = (L_t + m*T_t) * S_{t+m-p}

其中:
- p:季节周期长度(如 12 个月、7 天)
- γ:季节平滑系数(0 ≤ γ ≤ 1)
- S_t:t 时刻的季节因子
模型选择原则:
  • 加法模型: 季节波动幅度不随序列水平变化(如月销量波动 ±500 件,无论基线是 1000 还是 5000)。
  • 乘法模型: 季节波动幅度与水平成比例(如旺季销量是淡季的 1.5 倍,基线越高波动越大)。
Holt-Winters 三次指数平滑模型结构 历史时间序列 Y_t 水平分量 L_t 趋势分量 T_t 季节分量 S_t 预测值 F_{t+m} 三个平滑系数:α(水平)| β(趋势)| γ(季节) 加法模型:Y_t = L_t + T_t + S_t | 乘法模型:Y_t = (L_t + T_t) × S_t

3.4 Python 实现:Statsmodels 与手动调参

Python 的 statsmodels 库提供了完整的指数平滑实现。以下代码演示如何对带有趋势和季节性的供应链需求数据进行 Holt-Winters 建模与调参:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.holtwinters import ExponentialSmoothing

# 1. 生成模拟数据:月销量,含趋势和12个月季节周期
np.random.seed(42)
months = 48  # 4年数据
t = np.arange(months)
trend = 0.5 * t
seasonal = 10 * np.sin(2 * np.pi * t / 12)
noise = np.random.normal(0, 2, months)
sales = 100 + trend + seasonal + noise

df = pd.DataFrame({'month': pd.date_range('2020-01-01', periods=months, freq='M'),
                   'sales': sales})

# 2. 划分训练集和测试集
train = df.iloc[:36]   # 前3年训练
test = df.iloc[36:]    # 后1年测试

# 3. 构建 Holt-Winters 加法模型
model = ExponentialSmoothing(
    train['sales'],
    trend='add',          # 加法趋势
    seasonal='add',       # 加法季节
    seasonal_periods=12   # 12个月周期
)
fit = model.fit(
    smoothing_level=0.3,      # α
    smoothing_trend=0.1,      # β
    smoothing_seasonal=0.2,   # γ
    optimized=False           # 手动指定参数
)

# 4. 预测未来12个月
forecast = fit.forecast(12)

# 5. 评估预测效果
from sklearn.metrics import mean_absolute_error, mean_squared_error
mae = mean_absolute_error(test['sales'], forecast)
rmse = np.sqrt(mean_squared_error(test['sales'], forecast))
print(f"MAE: {mae:.2f}, RMSE: {rmse:.2f}")

# 6. 自动优化参数(推荐)
fit_auto = model.fit(optimized=True)  # 自动搜索最优 α, β, γ
forecast_auto = fit_auto.forecast(12)
mae_auto = mean_absolute_error(test['sales'], forecast_auto)
print(f"自动调参 MAE: {mae_auto:.2f}")

3.5 调参策略与网格搜索

手动调参效率低,实际项目中通常使用网格搜索(Grid Search)或贝叶斯优化自动寻找最优参数组合。以下是一个简单的网格搜索实现:

from itertools import product

# 定义参数搜索范围
alphas = np.arange(0.1, 0.9, 0.1)
betas = np.arange(0.05, 0.5, 0.05)
gammas = np.arange(0.05, 0.5, 0.05)

best_mae = float('inf')
best_params = {}

for alpha, beta, gamma in product(alphas, betas, gammas):
    try:
        fit = model.fit(
            smoothing_level=alpha,
            smoothing_trend=beta,
            smoothing_seasonal=gamma,
            optimized=False
        )
        forecast = fit.forecast(12)
        mae = mean_absolute_error(test['sales'], forecast)
        if mae < best_mae:
            best_mae = mae
            best_params = {'alpha': alpha, 'beta': beta, 'gamma': gamma}
    except:
        continue

print(f"最优参数: {best_params}, MAE: {best_mae:.2f}")
调参经验规则:
  • α(水平)通常在 0.1~0.5 之间,数据越平稳取值越小。
  • β(趋势)通常 ≤ 0.3,趋势突变时才考虑较大值。
  • γ(季节)通常在 0.05~0.3,季节模式越稳定取值越小。
  • 当数据量较大(≥ 5 个完整季节周期)时,优先使用 optimized=True 自动优化。

3.6 模型诊断与选择

选择哪种指数平滑模型,可通过以下步骤判断:

数据特征 推荐模型 关键参数
无趋势、无季节 一次指数平滑(SES) α
有趋势、无季节 二次指数平滑(Holt) α, β
有趋势、有季节(幅度恒定) Holt-Winters 加法 α, β, γ
有趋势、有季节(幅度随水平变化) Holt-Winters 乘法 α, β, γ
指数平滑模型选择决策流程 输入时间序列 有趋势? 一次指数平滑 二次指数平滑 有季节? 二次指数平滑 幅度恒定? Holt-Winters 加法 Holt-Winters 乘法

3.7 供应链应用注意事项

实战避坑指南:
  • 异常值处理: 指数平滑对异常值敏感,建模前需先进行异常检测与修正(如使用中位数替代法)。
  • 季节周期确认: 供应链数据常见周期为 7 天(周)、12 个月(年)、4 周(月结周期),需根据业务实际设定 seasonal_periods。
  • 预测步长限制: 指数平滑适合短期预测(1~3 个季节周期),长期预测误差会快速累积。
  • 参数稳定性: 建议每季度重新训练模型,检查参数是否发生显著漂移。