4. ARIMA模型:自回归(AR)、差分(I)、移动平均(MA)概念,ARIMA建模步骤与Python statsmodels实现
ARIMA(自回归积分滑动平均模型)是时间序列预测中最经典、应用最广泛的统计模型之一。在供应链需求预测场景中,ARIMA能够有效捕捉历史需求数据中的趋势、季节性和随机波动,为补货计划提供可靠的预测基准。本节将系统讲解ARIMA的三个核心组件、建模步骤以及Python实现方法。
4.1 ARIMA模型三要素:AR、I、MA
ARIMA模型由三个核心组件组合而成,每个组件解决时间序列中不同类型的模式。理解这三个组件是掌握ARIMA建模的基础。
| 组件 | 全称 | 参数符号 | 核心思想 | 适用场景 |
|---|---|---|---|---|
| AR | 自回归 (Autoregressive) | p | 当前值与前p期历史值的线性组合 | 序列存在持续性记忆效应 |
| I | 差分 (Integrated) | d | 对序列进行d阶差分使其平稳 | 序列存在趋势或非平稳性 |
| MA | 移动平均 (Moving Average) | q | 当前值与过去q期预测误差的线性组合 | 序列受随机冲击影响较大 |
4.1.1 自回归 (AR) 组件
AR组件假设当前时刻的观测值与前p个时刻的观测值存在线性关系。其数学表达式为:
Y_t = c + φ₁Y_{t-1} + φ₂Y_{t-2} + ... + φ_pY_{t-p} + ε_t
其中:
- Y_t:当前时刻的观测值
- c:常数项
- φ₁, φ₂, ..., φ_p:自回归系数,衡量各滞后项的影响权重
- ε_t:白噪声误差项
在供应链场景中,AR组件可以理解为:本周的需求量与前几周的需求量存在相关性。例如,促销活动后的需求回弹效应往往会在后续几周持续显现。
4.1.2 差分 (I) 组件
差分是使非平稳序列转化为平稳序列的关键操作。一阶差分定义为:
ΔY_t = Y_t - Y_{t-1}
当序列存在线性趋势时,一阶差分即可消除趋势;若存在二次趋势,则需要二阶差分。d值通常取0、1或2,极少超过2。
4.1.3 移动平均 (MA) 组件
MA组件使用过去q期的预测误差来修正当前预测。其数学表达式为:
Y_t = c + ε_t + θ₁ε_{t-1} + θ₂ε_{t-2} + ... + θ_qε_{t-q}
其中:
- ε_t:当前时刻的随机误差
- θ₁, θ₂, ..., θ_q:移动平均系数
MA组件擅长捕捉突发事件(如缺货、促销、天气异常)对后续需求的冲击效应。在供应链中,一次促销活动的影响通常会在后续2-4周内逐渐衰减,MA组件可以很好地建模这种衰减模式。
4.2 ARIMA模型完整形式
将三个组件组合,得到ARIMA(p,d,q)模型的完整表达式:
ΔᵈY_t = c + φ₁ΔᵈY_{t-1} + ... + φ_pΔᵈY_{t-p} + ε_t + θ₁ε_{t-1} + ... + θ_qε_{t-q}
其中Δᵈ表示d阶差分后的序列。模型的核心思想是:先通过差分消除非平稳性,再对平稳后的序列建立AR和MA组件。
- p值:偏自相关函数(PACF)在p阶后截尾
- q值:自相关函数(ACF)在q阶后截尾
- d值:差分后序列通过单位根检验(ADF检验)
4.3 ARIMA建模步骤
ARIMA建模遵循一套标准化的流程,共包含6个关键步骤:
- 数据可视化与预处理:绘制时间序列图,检查缺失值、异常值,确定序列的基本特征(趋势、季节性、周期性)。
- 平稳性检验:使用ADF检验或KPSS检验判断序列是否平稳。若p值大于0.05,则序列非平稳,需要进行差分。
- 差分处理:对非平稳序列进行d阶差分,直到序列通过平稳性检验。每次差分后重新检验。
- 模型定阶:通过ACF和PACF图初步确定p和q的取值范围,或使用信息准则(AIC/BIC)自动搜索最优参数。
- 模型拟合与诊断:使用极大似然估计拟合模型参数,检查残差是否为白噪声(Ljung-Box检验),残差应无自相关且服从正态分布。
- 模型评估与预测:使用滚动预测或回测评估模型性能(MAE、RMSE、MAPE),生成未来N期的预测值。
- 过度差分:d值过大导致序列信息丢失,预测方差增大
- 过拟合:p和q值过大导致模型复杂度过高,泛化能力下降
- 忽略季节性:对于周、月、季度周期明显的供应链数据,应使用SARIMA模型
4.4 ARIMA建模流程SVG图
下图展示了ARIMA建模的完整流程,从原始数据输入到最终预测输出:
4.5 Python statsmodels实现
statsmodels库提供了完整的ARIMA建模工具。以下代码演示从数据加载到预测的完整流程:
4.5.1 数据准备与平稳性检验
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings('ignore')
# 加载示例数据(供应链周需求数据)
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', periods=156, freq='W')
trend = np.linspace(100, 150, 156)
seasonal = 10 * np.sin(2 * np.pi * np.arange(156) / 52)
noise = np.random.normal(0, 5, 156)
demand = trend + seasonal + noise
df = pd.DataFrame({'date': dates, 'demand': demand})
df.set_index('date', inplace=True)
# 平稳性检验(ADF检验)
def adf_test(series):
result = adfuller(series.dropna())
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
print('结论: 序列平稳' if result[1] < 0.05 else '结论: 序列非平稳,需要差分')
return result[1] < 0.05
print("=== 原始序列平稳性检验 ===")
is_stationary = adf_test(df['demand'])
4.5.2 差分处理与模型定阶
# 一阶差分
df['demand_diff1'] = df['demand'].diff()
print("\n=== 一阶差分后平稳性检验 ===")
is_stationary_diff1 = adf_test(df['demand_diff1'])
# 绘制ACF和PACF图辅助定阶
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(df['demand_diff1'].dropna(), lags=20, ax=axes[0])
plot_pacf(df['demand_diff1'].dropna(), lags=20, ax=axes[1])
axes[0].set_title('ACF - 一阶差分后')
axes[1].set_title('PACF - 一阶差分后')
plt.tight_layout()
plt.show()
# 根据ACF/PACF图初步判断:p=2, d=1, q=2
# 实际应用中建议使用自动搜索
4.5.3 模型拟合与诊断
# 拟合ARIMA(2,1,2)模型
model = ARIMA(df['demand'], order=(2, 1, 2))
model_fit = model.fit()
print("\n=== 模型摘要 ===")
print(model_fit.summary())
# 残差诊断
residuals = model_fit.resid
# Ljung-Box检验
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_test = acorr_ljungbox(residuals, lags=[10], return_df=True)
print(f"\nLjung-Box检验p值: {lb_test['lb_pvalue'].values[0]:.4f}")
if lb_test['lb_pvalue'].values[0] > 0.05:
print("✅ 残差为白噪声,模型诊断通过")
else:
print("⚠️ 残差存在自相关,需要调整模型参数")
4.5.4 预测与结果可视化
# 预测未来12周
forecast_steps = 12
forecast = model_fit.forecast(steps=forecast_steps)
forecast_index = pd.date_range(start=df.index[-1] + pd.Timedelta(weeks=1),
periods=forecast_steps, freq='W')
forecast_series = pd.Series(forecast, index=forecast_index)
# 输出预测结果
print("\n=== 未来12周需求预测 ===")
forecast_df = pd.DataFrame({
'周次': range(1, forecast_steps + 1),
'预测日期': forecast_index.strftime('%Y-%m-%d'),
'预测需求量': forecast.values.round(1)
})
print(forecast_df.to_string(index=False))
4.6 模型参数自动搜索
手动定阶存在主观性,推荐使用网格搜索结合AIC准则自动寻找最优参数:
from itertools import product
# 定义参数搜索范围
p_range = range(0, 4)
d_range = range(0, 2)
q_range = range(0, 4)
best_aic = np.inf
best_order = None
best_model = None
print("=== 自动参数搜索 ===")
for p, d, q in product(p_range, d_range, q_range):
try:
model = ARIMA(df['demand'], order=(p, d, q))
model_fit = model.fit()
if model_fit.aic < best_aic:
best_aic = model_fit.aic
best_order = (p, d, q)
best_model = model_fit
print(f'ARIMA({p},{d},{q}) - AIC: {model_fit.aic:.2f}')
except:
continue
print(f'\n✅ 最优模型: ARIMA{best_order}, AIC={best_aic:.2f}')
4.7 ARIMA模型在供应链中的适用性分析
| 评估维度 | 优势 | 局限性 |
|---|---|---|
| 数据要求 | 仅需历史需求数据,无需外部特征 | 需要至少50-100个观测点才能稳定估计 |
| 趋势处理 | 差分机制可有效消除线性/非线性趋势 | 对突变趋势(如促销、新品上市)适应较慢 |
| 季节性 | 基础ARIMA不支持季节性,需扩展为SARIMA | 季节性周期较长时参数增多,易过拟合 |
| 预测时效 | 短期预测(1-4周)精度较高 | 长期预测(超过12周)误差累积明显 |
| 可解释性 | 参数含义明确,业务人员可理解 | 无法引入促销、价格、天气等外部变量 |
- 对于稳定品类(如日用品、基础原料),ARIMA是首选模型,预测精度高且维护成本低
- 对于促销驱动品类,建议使用ARIMAX(加入外部回归变量)或与机器学习模型集成
- 对于新品或短生命周期产品,数据量不足时优先使用简单指数平滑法
- 始终保留模型诊断环节:残差白噪声检验是模型可靠性的最后防线
4.8 ARIMA与简单预测方法对比SVG图
下图对比了ARIMA模型与简单预测方法在供应链需求预测中的表现差异:
4.9 本章小结
ARIMA模型通过自回归(AR)、差分(I)和移动平均(MA)三个组件的有机组合,为供应链需求预测提供了强大的统计建模框架。掌握ARIMA的核心在于理解三个组件的物理含义、遵循标准化的建模流程,以及熟练使用Python statsmodels库进行实现。在实际供应链项目中,ARIMA通常作为基准模型,与更复杂的机器学习模型形成互补,共同构建稳健的预测体系。