时间序列:带季节性的预测模型SARIMA
写在前面:
首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。
路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬步以至千里,就一定能够把宏伟目标变为美好现实。
Hello,大家好。前面我们完整讲解了 ARIMA(基础时序) 和 ARIMAX(带外部因子时序)。但在真实业务中,绝大多数数据都有一个共性:周期性、季节性。
例如:
- 每月销量,每年固定旺季、淡季
- 用电负荷,春夏秋冬呈现规律波动
- 客流数据,工作日、周末、节假日周期性变化
- 温度、环境传感器数据,具备日周期、年周期
普通ARIMA无法捕捉季节周期,导致预测严重滞后、偏差极大。这时候,时间序列季节预测神器SARIMA登场。
今天这篇文章,带你从零吃透SARIMA原理、参数含义、适用场景、自动定阶、完整代码实战。
在进入主题之前,给大家分享一下今日语录(摘抄自《天道》):
“我现在已经不和别人争吵了,因为我开始意识到,每个人都只能站在自己认知角度上考虑问题。有钱把事做好,没钱把人做好,你的好对别人来说,就像一颗糖,吃了就没了,而你的不好对别人就像一道伤疤,会永远存在”。
以下内容均结合参考资料与个人实操理解原创撰写,不存在滥用原创问题。

什么是SARIMA
SARIMA = 季节性ARIMA
一句话公式:
SARIMA = 趋势规律(ARIMA) + 季节周期规律
ARIMA只能学习数据的:趋势、波动、残差。
SARIMA在ARIMA基础上,额外增加了「季节周期建模能力」,专门解决周期性时序预测。也是工业、金融、能源、零售时序预测的标准baseline模型。
SARIMA模型参数
SARIMA完整表达式:SARIMA(p,d,q)(P,D,Q,s)
分为非季节部分和季节部分,8个参数全部讲明白:
非季节参数 (p,d,q)
p、d、q参数和ARIMA完全一致:
- p:自回归阶数,利用历史数据拟合当前值
- d:差分阶数,让非平稳数据变平稳
- q:移动平均阶数,修正预测残差误差
季节参数 (P,D,Q,s)
P,D,Q,s参数是SARIMA独有:
- P:季节自回归阶数
- D:季节差分阶数,消除季节趋势
- Q:季节移动平均阶数
- s:季节周期长度(最重要)
业务周期s万能对照表
s参数可以直接套用:
- 月度数据、年周期 → s=12
- 季度数据、年周期 →s=4
- 日数据、周周期 → s=7
- 小时数据、日周期 → s=24
- 5s/10s 高频传感器数据 → 根据业务周期自定义
ARIMA、ARIMAX、SARIMA三者区别
理清三者关系,不再混淆:
ARIMA
仅学习数据自身趋势,不支持季节、不支持外部变量,适合平稳无周期数据。
ARIMAX
ARIMA + 外生变量,支持外部因素(促销、天气、节假日),不支持季节建模。
SARIMA
ARIMA + 季节周期,支持周期规律,不支持外生变量。
既有季节又有外部因素?请直接上终极模型:SARIMAX(季节 + 外生变量)
SARIMA 适用场景
只要数据满足 周期性重复波动,优先使用SARIMA:
- 商品月度、季度销量预测
- 电网负荷、能耗时序预测
- 景区、商场客流周期预测
- 气温、环境、水文周期性数据
- 设备传感器周期性波动数据
代码实战
我们使用代码生成一份含季节性、周期性的时间序列数据:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.statespace.sarimax import SARIMAX
from sklearn.metrics import mean_squared_error, mean_absolute_error
import joblib
import warnings
warnings.filterwarnings('ignore')
# ===================== 1. 构造带季节性时序数据 =====================
np.random.seed(42)
n = 120
# 月度数据,周期12
dates = pd.date_range("2015-01-01", periods=n, freq="M")
# 趋势项 + 季节项 + 噪声
trend = np.linspace(2, 12, n)
season = 3 * np.sin(np.linspace(0, 10 * np.pi, n))
noise = np.random.normal(0, 0.8, n)
y = trend + season + noise
df = pd.DataFrame({"date": dates, "y": y})
df.set_index("date", inplace=True)
df.to_csv("data_sarima.csv")
# 查看趋势
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
plt.figure(figsize=(12,6))
plt.plot(df["y"], label="数据", color="#1f77b4")
数据集:

原始数据趋势:

训练模型代码:
# ===================== 2. 划分训练集、测试集 =====================
train = df.iloc[:-12]
test = df.iloc[-12:]
# ===================== 3. 自动最优SARIMA阶数选择 =====================
def best_sarima_order(data, s=12):
best_aic = float("inf")
best_order = (1,1,1)
best_seasonal_order = (1,1,1,s)
for p in range(3):
for d in range(2):
for q in range(3):
for P in range(2):
for D in range(2):
for Q in range(2):
try:
model = SARIMAX(data,order=(p,d,q),seasonal_order=(P,D,Q,s))
res = model.fit(disp=False)
if res.aic < best_aic:
best_aic = res.aic
best_order = (p,d,q)
best_seasonal_order = (P,D,Q,s)
except:
continue
return best_order, best_seasonal_order
order, seasonal_order = best_sarima_order(train["y"], s=12)
print("最优非季节阶数 order:", order)
print("最优季节阶数 seasonal_order:", seasonal_order)
# ===================== 4. 训练SARIMA模型 =====================
model = SARIMAX(
train["y"],
order=order,
seasonal_order=seasonal_order,
enforce_stationarity=False, # 关闭平稳性强校验
enforce_invertibility=False # 关闭可逆性强校验
# 两个开关设为 False 是工业界通用最优配置,减少报错、提升稳定性
)
model_fit = model.fit(disp=False)
print(model_fit.summary())
# ===================== 5. 预测未来12期 =====================
forecast = model_fit.get_forecast(steps=12)
pred_mean = forecast.predicted_mean
true_y = test["y"]
# ===================== 6. 模型评估 =====================
rmse = np.sqrt(mean_squared_error(true_y, pred_mean))
mae = mean_absolute_error(true_y, pred_mean)
print(f"\n【模型评估】\nRMSE: {rmse:.2f}\nMAE: {mae:.2f}")
# ===================== 7. 可视化 =====================
plt.figure(figsize=(12,6))
plt.plot(train["y"], label="训练数据", color="#1f77b4")
plt.plot(test["y"], label="真实值", color="#2ca02c")
plt.plot(test.index, pred_mean, label="SARIMA预测值", color="#d62728", linewidth=2)
plt.legend()
plt.grid(True, alpha=0.3)
plt.title("SARIMA 季节性时间序列预测结果")
plt.show()
# ===================== 8. 模型保存与加载(工程部署) =====================
# joblib.dump(model_fit, "sarima_best_model.pkl")
# print("✅ SARIMA模型保存成功")
# 加载复用
# model_load = joblib.load("sarima_best_model.pkl")
# pred = model_load.get_forecast(steps=12)
输出结果:
最优非季节阶数 order: (2, 1, 2)
最优季节阶数 seasonal_order: (1, 0, 1, 12)
SARIMAX Results
============================================================================================
Dep. Variable: y No. Observations: 108
Model: SARIMAX(2, 1, 2)x(1, 0, [1], 12) Log Likelihood -114.414
Date: Wed, 10 Jun 2026 AIC 242.828
Time: 21:41:16 BIC 260.480
Sample: 01-31-2015 HQIC 249.952
- 12-31-2023
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ar.L1 0.9087 0.141 6.448 0.000 0.632 1.185
ar.L2 0.0910 0.142 0.643 0.520 -0.186 0.368
ma.L1 -1.9966 2.956 -0.675 0.499 -7.791 3.798
ma.L2 0.9976 2.945 0.339 0.735 -4.774 6.769
ar.S.L12 -0.9602 0.014 -70.786 0.000 -0.987 -0.934
ma.S.L12 0.8910 0.295 3.022 0.003 0.313 1.469
sigma2 0.5136 1.608 0.319 0.749 -2.637 3.665
===================================================================================
Ljung-Box (L1) (Q): 0.10 Jarque-Bera (JB): 1.63
Prob(Q): 0.75 Prob(JB): 0.44
Heteroskedasticity (H): 0.85 Skew: -0.31
Prob(H) (two-sided): 0.65 Kurtosis: 2.82
===================================================================================
Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
【模型评估】
RMSE: 0.95
MAE: 0.78

预测效果还是不错的,感兴趣的可以找一个真实的业务场景去验证模型的效果。
总结
- 1、SARIMA是ARIMA的季节增强版,专门解决带周期性的时序预测问题。
- 2、核心新增 (P,D,Q,s)季节参数,其中周期s是建模成败关键。
- 3、相比ARIMA,SARIMA能精准捕捉淡旺季、昼夜、周度、年度规律,业务精度大幅提升。
- 4、沿着ARIMA → ARIMAX → SARIMA → SARIMAX学习路线,可以循序渐进吃透时间序列全套体系。
说明:文章首发在微信公众号
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)