写在前面:
首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。

路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬步以至千里,就一定能够把宏伟目标变为美好现实。

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学习路线,可以循序渐进吃透时间序列全套体系。

说明:文章首发在微信公众号

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐