此前篇章(平稳序列):
时间序列分析(一)——基础概念篇
时间序列分析(二)——平稳性检验
时间序列分析(三)——白噪声检验
时间序列分析(四)——差分运算、延迟算子、AR(p)模型
时间序列分析(五)——移动平均模型(MA模型)
时间序列分析(六)——自回归移动平均模型(ARMA模型)
时间序列分析(七)——平稳序列建模
此前篇章(非平稳序列):
非平稳时间序列分析(一)——时间序列的分解(wold、cramer)、差分运算
非平稳时间序列分析(二)——ARIMA(p, d, q)模型
一、季节性自回归移动平均模型(SARIMA)
模型原理
SARIMA 是 ARIMA 模型的扩展,专门处理时间序列中的 季节性成分,模型结构为 SARIMA(p, d, q)(P, D, Q)s
,其中:
非季节性部分:(p, d, q)
-
p
: 自回归项(AR)阶数,捕捉当前值与历史值的线性关系。 -
d
: 差分阶数,消除趋势。 -
q
: 移动平均项(MA)阶数,捕捉残差中的滞后误差。
季节性部分:(P, D, Q)s
-
P
: 季节性自回归阶数。 -
D
: 季节性差分阶数(周期为s
的差分,如月度数据s=12
)。 -
Q
: 季节性移动平均阶数。 -
s
: 季节周期长度(如月度数据s=12
,季度数据s=4
)。
SARIMA 模型的一般形式为:
其中,B 是滞后算子。
建模步骤
1、平稳 化数据
-
通过 差分 消除趋势和季节性
-
使用 ADF检验 或 KPSS检验 验证平稳性。
2、确定阶数
-
观察 ACF(自相关图) 和 PACF(偏自相关图):
-
非季节性阶数(
p
,q
):在滞后1, 2, ... 处显著。 -
季节性阶数(
P
,Q
):在滞后s
,2s
处显著。
-
-
使用 网格搜索 或 AIC/BIC准则 选择最优参数组合。
3、模型拟合与验证
-
检查残差是否为白噪声(Ljung-Box检验)。
-
预测时需逆差分还原原始数据。
import statsmodels.api as sm
# 示例:拟合SARIMA模型
model = sm.tsa.SARIMAX(
data,
order=(1, 1, 1), # 非季节部分 (p, d, q)
seasonal_order=(1, 1, 1, 12) # 季节部分 (P, D, Q, s)
)
result = model.fit()
result.summary()
# 预测未来12个时间点
forecast = result.get_forecast(steps=12)
print(forecast.predicted_mean)
问题 | 原因与解决方案 |
---|---|
过拟合 | 高阶参数(如 p=5, q=5)可能导致模型复杂,预测能力下降 → 优先选择 AIC/BIC 较小的模型。 |
多重季节性 | SARIMA 仅支持单一周期 → 使用 TBATS 或 Prophet 处理多周期(如小时+天+周)。 |
季节性突变 | 季节性模式随时间变化(如疫情导致消费习惯改变) → 使用 STL分解 或 Prophet。 |
计算复杂度高 | 高阶季节性参数(如 Q=2)导致计算耗时 → 使用 auto_arima 自动搜索最优参数。 |
二、STL 分解
原理:STL(Seasonal-Trend decomposition using LOESS)将时间序列分解为三个分量:
-
趋势(Trend):长期变化方向。
-
季节性(Seasonal):固定周期波动。
-
残差(Residual):无法解释的随机噪声。
核心特点
-
使用 LOESS(局部加权回归) 平滑方法,适应复杂季节性(如振幅变化的季节性)。
-
支持非固定周期的季节性(需手动指定周期
s
)。
建模步骤
1、分解时间序列
-
使用 STL 将数据拆分为趋势、季节性和残差。
2、 预测各分量
-
分别预测趋势和季节性,再合并结果。
-
残差通常假设为随机噪声,不进行预测。
from statsmodels.tsa.seasonal import STL
import pandas as pd
# 生成示例数据(假设 data 是时间序列)
data = pd.Series(...)
# STL 分解
stl = STL(data, period=12) # 周期 s=12(月度数据)
result = stl.fit()
# 绘制分解结果
result.plot()
plt.show()
# 提取各分量
trend = result.trend
seasonal = result.seasonal
residual = result.resid
# 预测(假设趋势用线性模型预测)
from sklearn.linear_model import LinearRegression
# 预测趋势
X = np.arange(len(data)).reshape(-1, 1)
model_trend = LinearRegression().fit(X, trend)
future_trend = model_trend.predict(np.arange(len(data), len(data)+12).reshape(-1, 1))
# 预测季节性(假设周期性重复)
future_seasonal = seasonal[-12:].values # 取最近一个周期的季节性
# 合并预测结果
forecast = future_trend + future_seasonal
问题 | 原因与解决方案 |
---|---|
趋势预测误差累积 | 若趋势用简单线性回归预测,长期预测可能偏离 → 使用 ARIMA 或 Prophet 建模趋势。 |
固定周期假设 | STL 需手动指定周期 s → 对非固定周期(如农历节假日)不适用 → 改用 Prophet。 |
高频数据计算耗时 | 对秒级/分钟级数据,LOESS 平滑计算量大 → 使用 移动平均 或 降采样。 |
极端值敏感 | 离群值可能扭曲趋势和季节性 → 预处理时需 去噪 或 鲁棒平滑。 |
三、Holt-Winters 季节性指数平滑
模型原理
Holt-Winters季节性指数平滑法是一种用于预测具有趋势和季节性成分的时间序列的有效方法,包含三个平滑参数:
-
水平(Level):序列的基线值。
-
趋势(Trend):序列的增长或下降速率。
-
季节性(Seasonal):周期性波动。
其中,以上三个参数都需要设立初始值,并有相应的计算公式(未列出)。
两种形式
-
加法模型:适用于季节性波动幅度不随时间变化的情况。
-
乘法模型:适用于季节性波动幅度随时间变化而变化的情况(如指数增长趋势)。
观察时间序列图:若季节峰谷的幅度随时间变化显著,选择乘法模型;否则选择加法模型。
建模步骤
-
选择模型类型:根据季节性是否随趋势变化选择加法或乘法模型。
-
初始化参数:通过第一个周期的数据,初始化水平Level、趋势和季节性。
-
优化参数:使用最小化均方误差(MSE)选择最优的 α,β,γ
案例 1:加法模型
-
场景:预测某城市月度平均气温。
-
分析:气温的年周期波动幅度稳定(每年夏季约30°C,冬季约5°C),适合加法模型。
案例 2:乘法模型
-
场景:预测电商平台季度销售额。
-
分析:销售额在“双11”期间的峰值随平台用户增长逐年放大,需用乘法模型。
from statsmodels.tsa.holtwinters import ExponentialSmoothing
# 拟合加法模型(additive)
model = ExponentialSmoothing(
data,
trend='add', # 趋势类型(add/mul)
seasonal='add', # 季节性类型(add/mul)
seasonal_periods=12 # 周期 s=12
)
result = model.fit()
# 预测未来12个时间点
forecast = result.forecast(12)
print("预测结果:", forecast)
# 查看平滑参数
print("alpha:", result.params['smoothing_level'])
print("beta:", result.params['smoothing_trend'])
print("gamma:", result.params['smoothing_seasonal'])
问题 | 原因与解决方案 |
---|---|
长期预测漂移 | 加法模型假设趋势线性增长,长期预测可能偏离 → 改用阻尼趋势(damped trend)。 |
对突变数据不敏感 | 平滑参数(如 α=0.1)导致模型响应滞后 → 增大 α |
仅支持单一季节性 | 无法处理小时+天的双重周期 → 使用 TBATS 或 Prophet。 |
初始值敏感 | 初始季节因子估计不准导致预测偏差 → 用多个周期数据初始化。 |
四、模型对比
场景 | 推荐模型 | 原因 |
---|---|---|
严格统计假设 | SARIMA | 数学形式严谨,适合学术研究和需置信区间的场景。 |
快速原型开发 | Holt-Winters | 参数少、实现简单,适合季节性明显且周期固定的业务数据。 |
复杂季节性 | STL + 机器学习 | STL分解后,可用XGBoost/LSTM预测趋势和残差,灵活性高。 |
# 文章如有错误,欢迎大家指正。我们下期再见叭