60天python训练计划----day59

在之前的学习中,我们层层递进的介绍了时序模型的发展,从AR到MA到ARMA,再到ARIMA。本质就是把数据处理的操作和模型结合在一起了,实际上昨天提到的季节性差分也可以合并到模型中,让流程变得更加统一。

季节性差分用S来表示,所以这个模型叫做SARIMA模型

一、SARIMA模型

SARIMA (Seasonal AutoRegressive Integrated Moving Average)是标准ARIMA模型的扩展。它专门用于处理具有明显季节性模式的时间序列数据。

可以把SARIMA想象成一个"双核"的ARIMA模型:

  1. 一个非季节性核心,用来处理数据的整体趋势。

  2. 一个季节性核心,用来处理数据中的周期性模式。

1.1 SARIMA模型的参数

SARIMA模型由两组参数定义:(p,d,q) 和 (P,D,Q,m)

ps:注意大小写

  1. 非季节性部分: (p, d, q) 这里和之前arima一致

  2. 季节性部分: (P, D, Q, m),这是一套全新的参数 (P, D, Q, m)。它负责处理序列的长期、周期性的依赖关系。

标准写法 SARIMA(p, d, q)(P, D, Q)m

这里之所以m单独拿出来,为了在概念上强调 m 的独特性

m 是舞台,P,D,Q 是演员

m 定义了季节性的"舞台"有多大。它不是一个需要通过模型拟合来"学习"的阶数,而是数据本身固有的、预先定义的结构性属性。m可以理解为季节周期。

在分析数据之初,我们通过观察或业务常识就能确定m。看到月度数据,我们立刻知道m=12;看到季度数据,我们知道m=4。

m 告诉模型:"你要关注的周期性规律是每隔m个时间点重复一次的。" 它为季节性核心 (P, D, Q) 的所有运算提供了基准尺度。

(P, D, Q)季节性阶数,它们描述了在这个季节性尺度上,模型的具体行为。

  • P: 在m的尺度上,需要看过去几个季节的自己?(y_{t-m}, y_{t-2m}, ...)

  • D: 在m的尺度上,需要做几次差分?(y_t - y_{t-m})

  • Q: 在m的尺度上,需要看过去几个季节的误差?(error_{t-m}, error_{t-2m}, ...)

这些阶数通常需要通过分析季节性差分后的ACF/PACF图来确定。

这里我们强调下(p,d,q)和(P,D,Q)的区别。差别在于它们看的不是上一个时间点,而是上一个季节的同一时间点。

普通差分 (d) 是 y_t - y_{t-1} (今天 - 昨天)。季节性差分 (D) 是 y_t - y_{t-m} (今年8月 - 去年8月)。

它的作用是消除季节性带来的增长趋势,让季节性数据变得平稳。如果用电量每年夏天都比上一年夏天高,D=1就能消除这个影响。

普通AR (p) 认为 y_t 和 y_{t-1}, y_{t-2}... 相关。季节性AR (P) 认为 y_t 和 y_{t-m}, y_{t-2m}... 相关。也就是说,模型认为今年8月的用电量和去年8月、前年8月的用电量有直接关系。

普通MA (q) 认为 y_t 的误差和 t-1, t-2 时刻的误差相关。季节性MA (Q) 认为 y_t 的误差和 t-m, t-2m 时刻的误差相关。也就是说,模型认为对今年8月的预测误差,可以根据去年8月、前年8月的预测误差来进行修正。

总结:季节性阶数是对比不同季节的同一时刻的差别。

1.2 SARIMA模型的理解

sarima不是单纯的对arima做了一次季节差分,而且做了季节性的一些其他特征捕捉:季节自回归P、季节移动平均Q。

SARIMA的完整工作流是这样的:

  1. 季节性层面分析:模型首先利用 (P, D, Q)m 这一套完整的"季节性ARIMA"来处理数据。它进行季节性差分(D),然后用季节性自回归(P)和季节性移动平均(Q)来解释季节性平稳后的数据中的模式。这个过程的输出是一个"季节性影响被剥离后"的残差序列。

  2. 非季节性层面分析:接着,模型再将我们熟悉的 (p, d, q) 应用于第一步产生的残差序列上。它对这个序列进行普通差分(d),然后用AR(p)和MA(q)来捕捉其中剩余的、短期的、非季节性的模式。

总结:SARIMA不是在ARIMA上打个补丁,而是构建了一个与非季节性部分 (p,d,q) 平行且完整的季节性分析系统 (P,D,Q)m。这两个系统协同工作,一个负责宏观的、周期性的规律,另一个负责微观的、短期的波动,最终结合成一个强大而全面的预测模型。

1.3 SARIMA实战

python 复制代码
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.statespace.sarimax import SARIMAX
import warnings
warnings.filterwarnings('ignore')
# 显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


# 1. 加载数据
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv'
df = pd.read_csv(url, header=0, index_col=0, parse_dates=True)
df.columns = ['Passengers']

# 2. 划分训练集和测试集(保留最后12个月作为测试)
train_data = df.iloc[:-12]
test_data = df.iloc[-12:]

print("--- 训练集 ---")
print(train_data.tail()) # 观察训练集最后5行
print("\n--- 测试集 ---")
print(test_data.head()) # 观察测试集前5行

# 3. 可视化原始数据
plt.figure(figsize=(12, 6))
plt.plot(train_data['Passengers'], label='训练集')
plt.plot(test_data['Passengers'], label='测试集', color='orange')
plt.title('国际航空乘客数量 (1949-1960)')
plt.xlabel('年份')
plt.ylabel('乘客数量 (千人)')
plt.legend()
plt.show()

# 进行季节性差分 (D=1, m=12)
seasonal_diff = df['Passengers'].diff(12).dropna()
# 再进行普通差分 (d=1)
seasonal_and_regular_diff = seasonal_diff.diff(1).dropna()

# 绘制差分后的数据
plt.figure(figsize=(12, 6))
plt.plot(seasonal_and_regular_diff)
plt.title('经过一次季节性差分和一次普通差分后的数据')
plt.show()

# ADF检验
result = adfuller(seasonal_and_regular_diff)
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}') # p-value越小,越说明数据平稳

# 绘制ACF和PACF图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
plot_acf(seasonal_and_regular_diff, lags=36, ax=ax1) # 绘制36个时间点
plot_pacf(seasonal_and_regular_diff, lags=36, ax=ax2)
plt.show()

from pmdarima import auto_arima # 一个方便的自动调参库
# 使用auto_arima自动寻找最优模型
# 我们告诉它d=1, D=1, m=12是固定的,让它去寻找p,q,P,Q的最优组合
# 默认使用AIC作为评估标准
auto_model = auto_arima(train_data['Passengers'],
                        start_p=0, start_q=0,
                        max_p=2, max_q=2,
                        m=12,
                        start_P=0, seasonal=True,
                        d=1, D=1,
                        trace=True,
                        error_action='ignore',
                        suppress_warnings=True,
                        stepwise=True)

print(auto_model.summary())

# 从auto_arima的结果中获取最优参数

best_order = auto_model.order
best_seasonal_order = auto_model.seasonal_order

# 拟合模型
model = SARIMAX(train_data['Passengers'],
                order=best_order,
                seasonal_order=best_seasonal_order)
results = model.fit(disp=False)

# 打印模型诊断图
results.plot_diagnostics(figsize=(15, 12))
plt.show()

# 预测未来12个点
predictions = results.get_prediction(start=test_data.index[0], end=test_data.index[-1])
pred_mean = predictions.predicted_mean # 预测均值
pred_ci = predictions.conf_int() # 预测的置信区间

# 绘制预测结果
plt.figure(figsize=(12, 6))
plt.plot(df['Passengers'], label='原始数据')
plt.plot(pred_mean, label='SARIMA 预测', color='red')
plt.fill_between(pred_ci.index,
                 pred_ci.iloc[:, 0],
                 pred_ci.iloc[:, 1], color='pink', alpha=0.5, label='置信区间')
plt.title('SARIMA模型预测 vs. 真实值')
plt.xlabel('年份')
plt.ylabel('乘客数量 (千人)')
plt.legend()
plt.show()

@浙大疏锦行

相关推荐
teeeeeeemo几秒前
回调函数 vs Promise vs async/await区别
开发语言·前端·javascript·笔记
加油吧zkf5 分钟前
AI大模型如何重塑软件开发流程?——结合目标检测的深度实践与代码示例
开发语言·图像处理·人工智能·python·yolo
t_hj6 分钟前
python规划
python
ejinxian20 分钟前
PHP 超文本预处理器 发布 8.5 版本
开发语言·php
czhc114007566321 分钟前
Linux 76 rsync
linux·运维·python
软件黑马王子1 小时前
C#系统学习第八章——字符串
开发语言·学习·c#
阿蒙Amon1 小时前
C#读写文件:多种方式详解
开发语言·数据库·c#
悠悠小茉莉1 小时前
Win11 安装 Visual Studio(保姆教程 - 更新至2025.07)
c++·ide·vscode·python·visualstudio·visual studio
Da_秀1 小时前
软件工程中耦合度
开发语言·后端·架构·软件工程
Fireworkitte1 小时前
Java 中导出包含多个 Sheet 的 Excel 文件
java·开发语言·excel