DAY 59 经典时序预测模型 2
作为零基础的 Python 和机器学习学习者,想要彻底搞懂经典时序预测模型 2 的 5 个核心知识点,我会用最接地气的语言、生活中的例子,搭配一步步的代码实操,把每个知识点拆解得明明白白,确保你能听懂、能上手。
一、先搞懂:时序建模的流程(像做饭一样简单)
你可以把时序建模理解成 “用过去的时间数据预测未来”,整个流程就像做一顿饭,步骤固定、逻辑清晰,零基础也能跟着走:
1. 流程拆解(用 “预测每月零花钱” 举例)
| 流程步骤 | 通俗解释(做饭类比) | 零花钱例子 |
|---|---|---|
| 数据获取 | 买菜(拿到原材料) | 收集过去 12 个月每月的零花钱(1000、1100、1200...) |
| 数据探索(EDA) | 洗菜、检查菜新不新鲜(看数据有没有问题) | 画折线图看零花钱是涨是跌、有没有异常(比如某月突然给了 5000) |
| 数据预处理 | 切菜、焯水(把数据变 “能用”) | 处理缺失值 / 异常值,把不平稳的零花钱数据变平稳(后面讲差分) |
| 模型选择与训练 | 炒菜(选菜谱 + 按步骤做) | 选 ARIMA 模型,用前 10 个月数据 “教” 模型找规律 |
| 模型评估 | 尝菜(看好不好吃) | 用模型预测后 2 个月零花钱,对比实际值,看误差大不大 |
| 模型调优 | 调味(咸了加汤、淡了加盐) | 调整 ARIMA 的参数(p,d,q),让预测更准 |
| 预测与部署 | 上菜(端给家人吃) | 用调好的模型预测下个月零花钱,指导自己花钱 |
2. 流程代码框架(可直接复制,注释超详细)
# 零基础友好:先导入必备工具(像做饭先拿锅碗瓢盆)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# ---------------------- 1. 数据获取 ----------------------
# 用Python内置的经典数据集AirPassengers(航空乘客数),不用自己找数据
# 数据格式:每月的航空乘客数量,是单变量时序数据
data = pd.read_csv(
'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv',
parse_dates=['Month'], # 把Month列识别为时间格式
index_col='Month' # 把时间列设为索引(时序数据必须的操作)
)
print("数据前5行:")
print(data.head()) # 看前5行数据,像检查买的菜新不新鲜
# ---------------------- 2. 数据探索(EDA) ----------------------
plt.figure(figsize=(10, 4)) # 设置图片大小
plt.plot(data, color='blue') # 画折线图
plt.title('每月航空乘客数(1949-1960)')
plt.xlabel('时间')
plt.ylabel('乘客数量')
plt.grid(True) # 加网格,看得更清楚
plt.show() # 显示图片(能看到数据整体上涨,还有季节性)
# ---------------------- 3. 数据预处理(先简单处理,后面详细讲) ----------------------
# 检查缺失值(像挑掉菜里的坏叶子)
print("\n缺失值数量:", data.isnull().sum()) # 这个数据集没有缺失值,新手不用处理
# ---------------------- 4. 模型选择与训练(先占位,后面ARIMA实战详细讲) ----------------------
# 这里先不写具体模型,只留框架,后面学ARIMA再填进去
# from statsmodels.tsa.arima.model import ARIMA
# model = ARIMA(data, order=(p,d,q)) # p,d,q后面讲
# result = model.fit()
# ---------------------- 5. 模型评估(占位) ----------------------
# 后面ARIMA实战会讲怎么算误差、看准不准
# ---------------------- 6. 模型调优(占位) ----------------------
# 后面会讲怎么调p,d,q参数
# ---------------------- 7. 预测(占位) ----------------------
# 后面ARIMA实战会讲怎么预测未来
二、时序任务经典单变量数据集(学写字先描红)
单变量时序数据 = 只有一列 “随时间变化的数值”(比如只有每月乘客数,没有其他列),这些经典数据集就像 “练字帖”,是所有新手必练的,用它们学模型最容易上手:
1. 4 个核心经典数据集(零基础先学第一个)
| 数据集名称 | 通俗解释 | 特点(为什么适合新手) |
|---|---|---|
| AirPassengers(航空乘客数) | 1949-1960 年每月坐飞机的人数 | 有明显的 “上升趋势”+“季节性”(年底人多),新手能直观看到规律 |
| Monthly Milk Production | 美国每月牛奶产量(磅) | 趋势 + 季节性,和 AirPassengers 类似,练手用 |
| Daily Minimum Temperatures | 澳大利亚墨尔本每日最低气温 | 有年度季节性(冬天冷、夏天热),无明显趋势 |
| Sunspots(太阳黑子数) | 每月太阳黑子的数量 | 周期性变化(约 11 年一个周期),适合学周期预测 |
2. 代码加载 + 可视化(以 AirPassengers 为例)
# 加载数据集(和上面流程里的代码一致,这里单独拿出来强调)
data = pd.read_csv(
'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv',
parse_dates=['Month'],
index_col='Month'
)
# 可视化(直观看到数据规律)
plt.figure(figsize=(12, 5))
plt.plot(data, marker='o', color='orange') # 加圆点,看得更清楚
plt.title('AirPassengers数据集:每月航空乘客数')
plt.xlabel('年份-月份')
plt.ylabel('乘客数量')
plt.axhline(y=data.mean(), color='red', linestyle='--', label='平均值') # 画平均值线
plt.legend()
plt.grid(True)
plt.show()
# 输出基本信息(了解数据)
print("数据集时间范围:", data.index.min(), "到", data.index.max())
print("数据总行数:", len(data)) # 144行,对应12年×12个月
运行后你会看到:折线一路向上(趋势),每年都有 “波峰”(比如每年 7/8 月)和 “波谷”(比如 1/2 月),这就是季节性 —— 新手能一眼看明白。
三、ARIMA(p,d,q)模型实战(时序预测的 “万能钥匙”)
ARIMA 是时序预测最基础、最核心的模型,专门解决 “单变量、不平稳” 的时序预测问题。先把 3 个参数掰碎了讲,再手把手实战。
1. 先搞懂 ARIMA 的 3 个参数(用 “零花钱” 举例,绝对通俗)
ARIMA = AR (p) + I (d) + MA (q),拆成 3 部分:
- p(AR 项,自回归项):“看过去 p 天的零花钱对今天的影响”比如 p=2,就是 “今天花多少钱” 和 “前 2 天分别花了多少钱” 有关系;p=0,就是和过去没关系。
- d(差分阶数):“把不平稳数据变平稳的次数”比如你的零花钱:1 月 1000、2 月 1100、3 月 1200(一直涨,不平稳),d=1 就是 “2 月 - 1 月 = 100,3 月 - 2 月 = 100”(变成平稳的固定值);如果 1 阶还不平稳,就 d=2(再差分一次)。
- q(MA 项,移动平均项):“看过去 q 天的预测误差对今天的影响”比如你预测昨天花 100,实际花 120(误差 + 20),这个误差会影响今天的预测;q=1 就是只看前 1 天的误差,q=2 看前 2 天。
2. ARIMA 实战步骤(从 0 到 1,代码 + 解释)
步骤 1:检查数据是否平稳(先 “体检”)
# 导入平稳性检验工具
from statsmodels.tsa.stattools import adfuller
# 定义平稳性检验函数(零基础直接用)
def check_stationary(data):
# ADF检验:p值<0.05说明数据平稳,否则不平稳
result = adfuller(data.values)
print('ADF检验p值:', result[1])
if result[1] < 0.05:
print("✅ 数据是平稳的")
else:
print("❌ 数据不平稳,需要差分")
# 检验AirPassengers数据
check_stationary(data) # 输出p值远大于0.05,说明不平稳
步骤 2:确定 d 值(差分让数据变平稳)
# 1阶差分:当前值 - 前一个值
data_diff1 = data.diff().dropna() # dropna去掉差分后的空值
# 可视化差分前后对比
plt.figure(figsize=(12, 6))
plt.subplot(2,1,1) # 画2行1列的第一个图
plt.plot(data, color='blue', label='原始数据')
plt.title('原始数据(不平稳)')
plt.grid(True)
plt.subplot(2,1,2) # 第二个图
plt.plot(data_diff1, color='green', label='1阶差分')
plt.title('1阶差分后数据')
plt.grid(True)
plt.tight_layout() # 调整布局,避免重叠
plt.show()
# 再次检验1阶差分后的数据
check_stationary(data_diff1) # 此时p值可能还是>0.05,说明需要再差分?
# (补充:AirPassengers有季节性,1阶差分只能去掉趋势,还需要季节性差分,后面讲)
# 新手先记:d=1是最常见的,大部分数据1阶差分就平稳了
步骤 3:确定 p 和 q 值(看 ACF/PACF 图)
# 导入ACF/PACF绘图工具
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 画ACF和PACF图(找p和q的参考值)
plt.figure(figsize=(12, 6))
plt.subplot(2,1,1)
plot_acf(data_diff1, lags=20, ax=plt.gca()) # ACF图:找q值(看曲线超出置信区间的滞后数)
plt.subplot(2,1,2)
plot_pacf(data_diff1, lags=20, ax=plt.gca(), method='ywm') # PACF图:找p值
plt.tight_layout()
plt.show()
# 新手简单判断:
# PACF图中,曲线第一次落到置信区间内的滞后数= p(比如PACF在lag=2时落进去,p=2)
# ACF图中,曲线第一次落到置信区间内的滞后数= q(比如ACF在lag=2时落进去,q=2)
# 这里先选p=1, d=1, q=1(新手先练手,后面调优)
步骤 4:训练 ARIMA 模型
# 导入ARIMA模型
from statsmodels.tsa.arima.model import ARIMA
# 拆分训练集和测试集(前120行训练,后24行测试)
train = data.iloc[:120] # 前10年数据
test = data.iloc[120:] # 后2年数据
# 训练ARIMA模型(order=(p,d,q))
model = ARIMA(train, order=(1,1,1)) # 先选p=1,d=1,q=1
result = model.fit()
# 输出模型摘要(后面SARIMA会详细讲)
print(result.summary())
步骤 5:预测 + 评估模型
# 预测测试集的24个月
pred = result.predict(start=len(train), end=len(train)+len(test)-1, typ='levels')
# typ='levels':预测原始数据尺度,不是差分后的数据
# 可视化预测结果
plt.figure(figsize=(12, 5))
plt.plot(train, label='训练集')
plt.plot(test, label='测试集(实际值)', color='green')
plt.plot(pred, label='预测值', color='red', linestyle='--')
plt.title('ARIMA(1,1,1)预测结果')
plt.xlabel('时间')
plt.ylabel('乘客数')
plt.legend()
plt.grid(True)
plt.show()
# 评估模型:计算均方误差(MSE),越小越准
from sklearn.metrics import mean_squared_error
mse = mean_squared_error(test, pred)
print(f"测试集均方误差(MSE):{mse:.2f}") # 数值越小,预测越准
3. 新手注意
- 第一次跑可能预测效果一般,因为我们选的 p=1,d=1,q=1 是 “默认值”,后面调优可以改成 p=2,d=1,q=2 等,误差会更小;
- ARIMA 适合 “只有趋势、没有明显季节性” 的数据,有季节性的话要用 SARIMA(后面讲)。
四、SARIMA 摘要图的理解(模型的 “成绩单”)
SARIMA 是 ARIMA 的 “升级版”,多了 4 个季节性参数:(P,D,Q,S),其中 S 是季节周期(比如月度数据 S=12,周度 S=7)。模型训练后输出的 “摘要图(summary)” 就是它的 “成绩单”,我们只看关键指标就行。
1. 先训练一个 SARIMA 模型(代码)
# 导入SARIMA模型
from statsmodels.tsa.statespace.sarimax import SARIMAX
# 训练SARIMA模型(order=ARIMA参数,seasonal_order=季节性参数)
# 选order=(1,1,1),seasonal_order=(1,1,1,12)(S=12,月度数据)
sarima_model = SARIMAX(train, order=(1,1,1), seasonal_order=(1,1,1,12))
sarima_result = sarima_model.fit()
# 输出摘要(重点看这个)
print(sarima_result.summary())
2. 摘要图关键指标解读(用 “成绩单” 类比)
| 指标名称 | 通俗解释 | 怎么看好不好 | ||
|---|---|---|---|---|
| Coefficients(系数)里的 P> | z | 每个参数的 “有效性得分”(类似考试分数) | <0.05:参数有用;>0.05:参数没用,要调整 | |
| sigma2 | 模型的 “误差方差”(类似做题的错题数) | 越小越好 | ||
| Log Likelihood | 对数似然值(类似总分) | 越大越好 | ||
| AIC/BIC | 信息准则(类似综合评分) | 越小越好 | ||
| Ljung-Box (Q) test | 残差检验(看模型有没有学完所有规律) | p 值 > 0.05:残差是白噪声(模型学透了) |
3. 新手简化版解读
不用看所有内容,只盯 3 个:
- 大部分 P>|z| < 0.05 → 参数选得还行;
- AIC/BIC 数值比之前的 ARIMA 小 → SARIMA 更适合;
- Ljung-Box 的 p 值 > 0.05 → 模型把数据规律都学了。
五、处理不平稳的 2 种差分(数据的 “平摊术”)
不平稳的数据就像 “斜着的地面”,模型站不稳,差分就是把 “斜地面” 掰平。核心是 2 种差分,分别解决 2 个问题:
1. n 阶差分(处理 “趋势”—— 比如数据一直涨 / 一直跌)
- 通俗解释:比如你每年的身高:10 岁 140cm、11 岁 150cm、12 岁 160cm(一直涨,有趋势,不平稳)。
- 1 阶差分:11 岁 - 10 岁 = 10cm,12 岁 - 11 岁 = 10cm(变成固定值,平稳了);
- 如果 1 阶还不平,就 2 阶差分(差分结果再差分),这就是 n 阶。
- 代码实战:
# 模拟有趋势的身高数据
height = pd.Series([140, 150, 160, 170, 180], index=pd.date_range('2020', periods=5, freq='Y'))
print("原始身高数据(有趋势):")
print(height)
# 1阶差分
height_diff1 = height.diff().dropna()
print("\n1阶差分后(去掉趋势):")
print(height_diff1) # 输出:10,10,10,10(平稳)
# 2阶差分(这里没必要,只是演示)
height_diff2 = height_diff1.diff().dropna()
print("\n2阶差分后:")
print(height_diff2) # 输出:0,0,0(完全平稳)
2. 季节性差分(处理 “季节性”—— 比如每年 7 月销量高)
- 通俗解释:比如雪糕销量:2021 年 7 月 1000 支、2022 年 7 月 1200 支、2023 年 7 月 1300 支(每年 7 月都高,有季节性)。季节性差分 = 本月数据 - 去年同月数据(比如 2022 年 7 月 - 2021 年 7 月 = 200,2023 年 7 月 - 2022 年 7 月 = 100),去掉季节性波动。关键:S(季节周期)—— 月度数据 S=12,周度 S=7,日度 S=365。
- 代码实战:
# 用AirPassengers演示季节性差分(S=12)
# 季节性差分:当前值 - 12个月前的值
data_season_diff = data.diff(12).dropna() # diff(12)就是减12个月前的值
# 可视化
plt.figure(figsize=(12, 6))
plt.subplot(2,1,1)
plt.plot(data, label='原始数据(趋势+季节性)')
plt.title('原始数据')
plt.grid(True)
plt.subplot(2,1,2)
plt.plot(data_season_diff, label='季节性差分(S=12)')
plt.title('季节性差分后(去掉季节性)')
plt.grid(True)
plt.tight_layout()
plt.show()
# 检验平稳性
check_stationary(data_season_diff) # 此时p值<0.05,数据平稳了!
3. 新手总结:什么时候用哪种差分?
- 数据只有 “趋势”(一直涨 / 跌)→ 用 n 阶差分(一般 d=1);
- 数据有 “季节性”(固定周期波动)→ 用季节性差分(S = 周期数);
- 数据既有趋势又有季节性→ 先 n 阶差分,再季节性差分(或反过来)。
总结(核心知识点回顾)
- 时序建模流程:核心是 “获取数据→探索→预处理→建模→评估→调优→预测”,像做饭一样按步骤来,缺一不可;
- 经典单变量数据集:AirPassengers 是新手首选,有趋势 + 季节性,练手最适合;
- ARIMA(p,d,q):p 看过去数据的影响,d 是差分次数,q 看过去误差的影响,核心是先把数据变平稳再建模;
- SARIMA 摘要图:重点看 P>|z|(<0.05)、AIC/BIC(越小越好)、Ljung-Box p 值(>0.05);
- 两种差分:n 阶差分处理 “趋势”,季节性差分处理 “季节性”,目的都是把数据变平稳。
你可以先把上面的代码逐行复制运行,看每个步骤的输出,再结合例子理解概念 —— 零基础不用急,先把 “平稳性”“差分”“ARIMA 参数” 这 3 个核心记牢,后面慢慢练就能掌握。

如何用代码实现时序建模流程中的数据获取和探索?
你想要用 Python 代码完整实现时序建模流程中的数据获取和数据探索(EDA) 两个核心步骤,作为零基础学习者,我会把代码写得极致详细(每一行都加注释),并逐一解释每一步的目的、输出含义,确保你不仅能跑通代码,还能理解背后的逻辑。
一、完整代码实现(零基础友好,可直接复制运行)
步骤 1:导入必备库(先 “准备工具”)
# 导入数据处理核心库:pandas用于处理表格数据,numpy用于数值计算
import pandas as pd
import numpy as np
# 导入可视化库:matplotlib用于画图,让数据“看得见”
import matplotlib.pyplot as plt
# 设置中文显示(避免画图时中文乱码,新手必加)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用黑体显示中文
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 导入平稳性检验工具:ADF检验是判断时序数据是否平稳的核心方法
from statsmodels.tsa.stattools import adfuller
步骤 2:数据获取(两种方式,新手优先选在线获取)
时序数据获取的核心是确保时间列是 “时间格式”,且作为数据的索引(方便后续分析)。
# 方式1:在线获取经典的AirPassengers数据集(无需本地文件,新手首选)
# 数据说明:1949-1960年每月航空乘客数量,是单变量时序数据的标杆
data = pd.read_csv(
'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv',
parse_dates=['Month'], # 关键:把"Month"列从文本转为“时间格式”
index_col='Month' # 关键:把时间列设为数据的“索引”(时序数据必须)
)
# 方式2:如果本地有CSV文件(比如文件叫airpassengers.csv),用下面代码
# data = pd.read_csv(
# 'airpassengers.csv', # 本地文件路径
# parse_dates=['Month'],
# index_col='Month'
# )
# 打印数据的前5行,快速查看数据结构(像“开箱检查”)
print("===== 数据前5行(预览) =====")
print(data.head())
步骤 3:数据探索(核心环节,从 “宏观” 到 “微观” 分析)
数据探索的目的是:① 检查数据有没有问题(缺失、异常);② 发现数据规律(趋势、季节性);③ 判断数据是否平稳。
# ---------------------- 3.1 基础信息检查(看数据“健康状况”) ----------------------
print("\n===== 数据基础信息 =====")
# 查看数据维度(行数×列数):AirPassengers是144行(12年×12月)×1列(乘客数)
print(f"数据维度(行数×列数):{data.shape}")
# 查看数据类型:确保时间索引是datetime,数值列是数值型
print("\n数据类型信息:")
print(data.info())
# 检查缺失值(时序数据最常见的问题之一)
print("\n缺失值数量:")
print(data.isnull().sum()) # AirPassengers无缺失值,输出0
# ---------------------- 3.2 描述性统计(用数字总结数据) ----------------------
print("\n===== 描述性统计(数值特征) =====")
# 输出均值、中位数、最大值、最小值等,快速了解数据的数值范围
print(data.describe())
# 关键解读:
# - count:有效数据量(144,无缺失)
# - mean:平均每月乘客数≈280人
# - max/min:最多622人,最少104人
# - std:标准差(越大说明数据波动越大)
# ---------------------- 3.3 时间索引检查(确保时序维度正确) ----------------------
print("\n===== 时间索引信息 =====")
# 查看数据的时间范围(起始+结束)
print(f"数据时间范围:{data.index.min()} 到 {data.index.max()}")
# 查看时间频率(确认是“月度数据”)
print(f"数据的时间频率:{pd.infer_freq(data.index)}") # 输出'M',代表月度(Month)
# ---------------------- 3.4 可视化探索(核心!用图形发现规律) ----------------------
# 3.4.1 整体趋势图(看数据是涨是跌)
plt.figure(figsize=(12, 8)) # 设置画布大小(宽12,高8)
# 子图1:整体趋势
plt.subplot(2, 2, 1) # 把画布分成2行2列,画在第1个位置
plt.plot(data, color='blue', linewidth=1.5) # 画折线图
plt.title('1949-1960年每月航空乘客数(整体趋势)')
plt.xlabel('时间')
plt.ylabel('乘客数量')
plt.grid(True, alpha=0.3) # 加网格,看得更清楚
# 3.4.2 年度均值趋势(看每年的整体变化)
plt.subplot(2, 2, 2)
# 按年分组计算均值:resample('Y')=按年重采样,mean()=求均值
data_yearly = data.resample('Y').mean()
plt.plot(data_yearly, color='red', marker='o')
plt.title('年度平均乘客数(年度趋势)')
plt.xlabel('年份')
plt.ylabel('平均乘客数')
plt.grid(True, alpha=0.3)
# 3.4.3 月度箱线图(看季节性:每月的分布差异)
plt.subplot(2, 2, 3)
# 提取月份(1-12),作为分组依据
data['月份'] = data.index.month
# 按月份画箱线图,看不同月份的乘客数分布
data.boxplot(column='Passengers', by='月份', grid=False)
plt.title('各月份乘客数分布(季节性)')
plt.xlabel('月份')
plt.ylabel('乘客数量')
plt.suptitle('') # 去掉默认标题,避免重叠
# 3.4.4 滚动均值+滚动标准差(判断平稳性)
plt.subplot(2, 2, 4)
# 滚动均值:每12个月的平均(窗口=12,对应一年)
roll_mean = data['Passengers'].rolling(window=12).mean()
# 滚动标准差:每12个月的波动
roll_std = data['Passengers'].rolling(window=12).std()
# 画图
plt.plot(data['Passengers'], label='原始数据', color='blue')
plt.plot(roll_mean, label='12个月滚动均值', color='red')
plt.plot(roll_std, label='12个月滚动标准差', color='green')
plt.title('滚动均值+标准差(平稳性判断)')
plt.xlabel('时间')
plt.ylabel('乘客数量')
plt.legend()
plt.grid(True, alpha=0.3)
# 调整子图间距,避免重叠
plt.tight_layout()
# 显示所有图形
plt.show()
# ---------------------- 3.5 平稳性定量检验(ADF检验) ----------------------
# 定义一个函数,封装ADF检验(新手可以直接复用)
def adf_test(series):
"""
执行ADF平稳性检验,输出关键结果
参数:series - 要检验的时序数据列
"""
print("\n===== ADF平稳性检验结果 =====")
# 执行ADF检验
result = adfuller(series)
# 输出检验结果
print(f'ADF统计量:{result[0]:.4f}')
print(f'p值:{result[1]:.4f}')
print(f'临界值:')
for key, value in result[4].items():
print(f' {key}: {value:.4f}')
# 核心判断:p值 < 0.05 → 数据平稳;否则不平稳
if result[1] < 0.05:
print("→ 结论:数据是平稳的")
else:
print("→ 结论:数据不平稳,需要后续差分处理")
# 对乘客数列执行ADF检验
adf_test(data['Passengers'])
二、代码运行结果解读(零基础必看)
1. 数据预览(前 5 行)

解读:索引是 “Month”(时间),列是 “Passengers”(乘客数),符合单变量时序数据的格式。
2. 基础信息 + 描述性统计
- 维度:
(144, 1)→ 144 行数据,1 列特征; - 缺失值:
0→ 数据完整; - 描述性统计:均值≈280,最大值 622,最小值 104 → 数据整体呈上升趋势。
3. 可视化结果
- 整体趋势图:折线一路向上 → 有长期增长趋势;
- 年度均值图:每年的均值都比前一年高 → 趋势明显;
- 月度箱线图:7、8 月乘客数明显更高 → 有季节性(年度周期);
- 滚动均值 / 标准差:均值持续上升,标准差也变大 → 数据不平稳。
4. ADF 检验结果
p 值远大于 0.05 → 定量验证数据不平稳,后续需要用差分处理。
三、总结(核心关键点)

你可以把这段代码完整复制到 Python 环境(比如 Jupyter、PyCharm)中运行,逐行看输出,对照解读理解每一步的意义 —— 数据获取和探索是时序建模的 “地基”,这一步做扎实了,后续建模会轻松很多。
除了ADF检验,还有哪些方法判断平稳性?
想知道除了 ADF 检验之外,还有哪些能判断时序数据平稳性的方法,作为零基础学习者,我会用最通俗的语言讲解这些方法的核心逻辑、判断规则,还会搭配可直接运行的代码(还是用你熟悉的 AirPassengers 数据集),让你既能理解原理,又能动手验证。
先回顾一下:平稳数据的核心特征是 “均值、方差、自相关性不随时间变化”—— 就像平静的湖面,不会一边高一边低,波动也均匀;而非平稳数据就像倾斜的山坡,要么一直涨 / 跌(趋势),要么波动忽大忽小(方差不稳定)。
下面讲 4 种常用的平稳性判断方法(除 ADF 外),按 “新手易理解程度” 排序:
一、可视化判断法(最直观,新手首选)
这是零基础最容易上手的方法,不用看复杂的统计值,直接从图里看规律,核心是 2 个图:
1. 滚动统计量(滚动均值 + 滚动标准差)

import pandas as pd
import matplotlib.pyplot as plt
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 加载数据
data = pd.read_csv(
'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv',
parse_dates=['Month'],
index_col='Month'
)
# 计算滚动统计量(窗口=12,对应1年周期)
window = 12
roll_mean = data['Passengers'].rolling(window=window).mean() # 滚动均值
roll_std = data['Passengers'].rolling(window=window).std() # 滚动标准差
# 画图
plt.figure(figsize=(10, 6))
plt.plot(data['Passengers'], label='原始数据', color='blue')
plt.plot(roll_mean, label=f'{window}个月滚动均值', color='red', linewidth=2)
plt.plot(roll_std, label=f'{window}个月滚动标准差', color='green', linewidth=2)
plt.title('滚动均值+标准差判断平稳性')
plt.xlabel('时间')
plt.ylabel('乘客数量')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 结果解读(AirPassengers数据):
# 滚动均值一路上升 → 均值随时间变;滚动标准差也上升 → 方差随时间变 → 不平稳
2. 自相关函数图(ACF 图)

from statsmodels.graphics.tsaplots import plot_acf
# 画原始数据的ACF图
plt.figure(figsize=(10, 4))
plot_acf(data['Passengers'], lags=30, ax=plt.gca()) # lags=30:看前30期的自相关
plt.title('原始数据ACF图(判断平稳性)')
plt.xlabel('滞后数(月份)')
plt.ylabel('自相关系数')
plt.grid(alpha=0.3)
plt.show()
# 结果解读(AirPassengers数据):
# ACF值从1缓慢下降,滞后20还在置信区间外 → 不平稳;
# 对比:如果是平稳数据(比如1阶差分后),ACF值会快速跌到0以下。
二、KPSS 检验(和 ADF 互补的 “黄金搭档”)
ADF 检验和 KPSS 检验是一对 “互补检验”,单独用一个容易误判,结合用更准:
- ADF 检验:假设 “数据不平稳(有单位根)”,p<0.05 → 推翻假设(数据平稳);
- KPSS 检验:假设 “数据平稳(趋势平稳)”,p>0.05 → 接受假设(数据平稳)。
1. 通俗原理
就像判断一个人 “是否健康”:ADF 是 “先假设他生病,找证据证明没病”,KPSS 是 “先假设他健康,找证据证明生病”,两个都验证才靠谱。
2. 判断规则
- p 值 > 0.05 → 数据平稳(符合 “趋势平稳” 假设);
- p 值 < 0.05 → 数据不平稳(推翻假设)。
3. 代码实现
from statsmodels.tsa.stattools import kpss
# 定义KPSS检验函数(零基础复用)
def kpss_test(series, regression='c'):
"""
regression参数:
- 'c':检验“水平平稳”(无趋势);
- 'ct':检验“趋势平稳”(有趋势但整体平稳)
"""
print("===== KPSS平稳性检验结果 =====")
result = kpss(series, regression=regression)
print(f'KPSS统计量:{result[0]:.4f}')
print(f'p值:{result[1]:.4f}')
print(f'临界值:')
for key, value in result[3].items():
print(f' {key}: {value:.4f}')
# 判断结论
if result[1] > 0.05:
print("→ 结论:数据平稳(接受KPSS平稳假设)")
else:
print("→ 结论:数据不平稳(推翻KPSS平稳假设)")
# 对AirPassengers数据做KPSS检验
kpss_test(data['Passengers'], regression='ct')
# 结果解读:
# AirPassengers的KPSS p值<<0.05 → 不平稳,和ADF检验结论一致。
三、PP 检验(ADF 的 “升级版”,更稳健)
PP 检验(Phillips-Perron 检验)是 ADF 检验的改进版,解决了 ADF 对 “异方差”(数据波动忽大忽小)敏感的问题,结果更可靠。
1. 通俗原理
ADF 检验要求数据 “波动均匀”,如果数据波动忽大忽小(比如乘客数后期波动比前期大),ADF 结果可能不准;PP 检验能 “修正” 这种波动,给出更稳健的判断,逻辑和 ADF 完全一样。
2. 判断规则
- p 值 < 0.05 → 数据平稳;
- p 值 > 0.05 → 数据不平稳。
3. 代码实现
from statsmodels.tsa.stattools import ppunitroot
# 定义PP检验函数
def pp_test(series):
print("===== PP平稳性检验结果 =====")
result = ppunitroot(series)
print(f'PP统计量:{result[0]:.4f}')
print(f'p值:{result[1]:.4f}')
print(f'临界值:')
for key, value in result[4].items():
print(f' {key}: {value:.4f}')
if result[1] < 0.05:
print("→ 结论:数据平稳")
else:
print("→ 结论:数据不平稳")
# 对AirPassengers做PP检验
pp_test(data['Passengers'])
# 结果解读:
# PP检验p值>>0.05 → 数据不平稳,和ADF/KPSS结论一致。
四、方差比检验(新手快速判断法)
这是最简单粗暴的方法,不用记复杂的统计原理,核心是 “对比不同时间段的方差”。
1. 通俗原理
平稳数据的方差是稳定的,所以 “前半段数据的方差” 和 “后半段数据的方差” 比值≈1;如果比值偏离 1(比如 > 1.5 或 < 0.5),说明方差不稳定,数据不平稳。
2. 判断规则
- 方差比 ≈ 1(0.8~1.2 之间)→ 方差稳定(平稳);
- 方差比 偏离 1 → 方差不稳定(不平稳)。
3. 代码实现
# 定义方差比检验函数
def variance_ratio_test(series):
print("===== 方差比平稳性检验结果 =====")
# 把数据分成前后两半
mid = len(series) // 2
first_half = series[:mid]
second_half = series[mid:]
# 计算两半的方差
var1 = first_half.var()
var2 = second_half.var()
# 计算方差比(后半/前半)
var_ratio = var2 / var1
print(f'前半段方差:{var1:.2f}')
print(f'后半段方差:{var2:.2f}')
print(f'方差比(后半/前半):{var_ratio:.2f}')
# 判断结论
if 0.8 <= var_ratio <= 1.2:
print("→ 结论:方差稳定,数据大概率平稳")
else:
print("→ 结论:方差不稳定,数据不平稳")
# 对AirPassengers做方差比检验
variance_ratio_test(data['Passengers'])
# 结果解读:
# AirPassengers前半段方差≈1000,后半段≈25000,方差比≈25 → 远大于1 → 不平稳。
五、实战对比:用所有方法验证同一数据
我们用 “1 阶差分后的 AirPassengers 数据”(理论上更平稳)跑所有方法,看结论是否一致:
# 1阶差分(去掉趋势)
data_diff1 = data['Passengers'].diff().dropna()
# 1. 可视化:滚动统计量
plt.figure(figsize=(10, 4))
roll_mean = data_diff1.rolling(window=12).mean()
roll_std = data_diff1.rolling(window=12).std()
plt.plot(data_diff1, label='1阶差分数据')
plt.plot(roll_mean, label='滚动均值', color='red')
plt.plot(roll_std, label='滚动标准差', color='green')
plt.title('1阶差分后滚动统计量')
plt.legend()
plt.show()
# 2. ACF图
plt.figure(figsize=(10, 4))
plot_acf(data_diff1, lags=30, ax=plt.gca())
plt.title('1阶差分后ACF图')
plt.show()
# 3. KPSS检验
kpss_test(data_diff1, regression='c')
# 4. PP检验
pp_test(data_diff1)
# 5. 方差比检验
variance_ratio_test(data_diff1)
# 结果总结:
# 1阶差分后,滚动均值/标准差基本水平 → ACF快速衰减 → KPSS p>0.05 → PP p<0.05 → 方差比≈1 → 数据平稳。
总结(核心关键点)

这些方法你可以逐个运行代码,对比原始数据和差分后数据的结果,就能直观感受到 “平稳数据” 和 “不平稳数据” 在各检验中的差异 —— 零基础不用死记原理,先跑通代码,看结果,慢慢就理解了。
如何选择ARIMA模型的阶数(p、d、q)?
你想知道如何精准选择 ARIMA 模型的核心阶数(p、d、q),作为零基础学习者,我会打破 “凭感觉选” 的误区,用 “先定 d→再找 p 和 q” 的固定逻辑,结合你刚实操过的太阳黑子数据集,用最通俗的语言 + 可直接运行的代码,把选阶数的方法拆成新手能无脑套用的步骤,确保你不仅懂原理,还能动手选出最优参数。
核心逻辑先明确
选阶数的核心顺序是:先定 d(差分阶数)→ 再定 p(AR 项)和 q(MA 项)
- d 是 “基础”:解决数据平稳性,没定对 d,p/q 选得再准也没用;
- p/q 是 “优化”:基于平稳后的数据,找能捕捉数据规律的最优值。
一、第一步:确定 d(差分阶数)—— 最容易,有固定规则
d 的作用是把不平稳数据变平稳,选 d 的核心是 “试到平稳为止,最多试 2 阶,绝对不试 3 阶及以上”。
选 d 的 3 个实操步骤(新手无脑套)
- 检验原始数据平稳性:用 ADF+KPSS 双重检验,若平稳→d=0;
- 试 1 阶差分:对原始数据做 1 阶差分,再检验平稳性,若平稳→d=1;
- 试 2 阶差分:若 1 阶还不平稳,做 2 阶差分,检验平稳性→d=2;
- 绝对不试 3 阶:3 阶及以上属于 “过度差分”,会丢失数据规律。
代码实操(太阳黑子数据集为例)
import pandas as pd
from statsmodels.tsa.stattools import adfuller, kpss
import warnings
warnings.filterwarnings('ignore')
# 加载太阳黑子数据(和之前作业一致)
from statsmodels.datasets import sunspots
data = sunspots.load_pandas().data
data['date'] = pd.to_datetime(data['YEAR'].astype(int).astype(str) + '-01-01')
data = data.set_index('date')[['SUNACTIVITY']]
data.columns = ['sunspots']
series = data['sunspots']
# 定义平稳性检验函数(核心工具)
def check_stationary(series):
adf_p = adfuller(series)[1]
kpss_p = kpss(series, regression='c')[1]
print(f"ADF p值:{adf_p:.4f} | KPSS p值:{kpss_p:.4f}")
return adf_p < 0.05 and kpss_p > 0.05
# 步骤1:检验原始数据
print("【原始数据】", "平稳" if check_stationary(series) else "不平稳") # 输出:不平稳
# 步骤2:1阶差分
diff1 = series.diff().dropna()
print("【1阶差分】", "平稳" if check_stationary(diff1) else "不平稳") # 输出:平稳 → d=1
# (如果1阶不平稳,再试2阶)
# diff2 = diff1.diff().dropna()
# print("【2阶差分】", "平稳" if check_stationary(diff2) else "不平稳")
结果:太阳黑子数据 1 阶差分就平稳 → d=1(这是最终确定的 d 值)。
二、第二步:确定 p 和 q—— 两种方法(新手→进阶)
p 是 AR 项(自回归项),q 是 MA 项(移动平均项),选法分两种:新手用 “ACF/PACF 图法”(直观),进阶用 “信息准则法”(精准)。
方法 1:ACF/PACF 图法(新手首选,可视化)
核心逻辑(记牢这 4 条,零基础也能判)
| 模型类型 | PACF 图特征(定 p) | ACF 图特征(定 q) |
|---|---|---|
| AR(p) | 在 lag=p 处 “截断”(突然落到置信区间内) | 缓慢衰减 |
| MA(q) | 缓慢衰减 | 在 lag=q 处 “截断”(突然落到置信区间内) |
| ARMA(p,q) | PACF 在 p 处截断,ACF 在 q 处截断 | PACF 在 p 处截断,ACF 在 q 处截断 |
实操步骤
- 用平稳后的数据(比如太阳黑子的 1 阶差分数据)画 ACF/PACF 图;
- 看 PACF 图 “第一次截断” 的滞后数→p;
- 看 ACF 图 “第一次截断” 的滞后数→q;
- 新手可先选 “小值”(p/q≤5),避免过度拟合。
代码实操
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# Mac中文适配
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 用1阶差分后的平稳数据画图
plt.figure(figsize=(12, 4))
# 子图1:PACF图(定p)
plt.subplot(1,2,1)
plot_pacf(diff1, lags=30, ax=plt.gca(), method='ywm') # lags=30:看前30期
plt.title('PACF图(定p)- 太阳黑子1阶差分数据')
plt.axvline(x=2, color='red', linestyle='--') # 标记p=2
# 子图2:ACF图(定q)
plt.subplot(1,2,2)
plot_acf(diff1, lags=30, ax=plt.gca())
plt.title('ACF图(定q)- 太阳黑子1阶差分数据')
plt.axvline(x=2, color='red', linestyle='--') # 标记q=2
plt.tight_layout()
plt.show()
结果解读:
- PACF 图在 lag=2 处突然落到置信区间内→p=2;
- ACF 图在 lag=2 处突然落到置信区间内→q=2;
- 初步确定:p=2,q=2(结合之前的 d=1,ARIMA (2,1,2))。
方法 2:信息准则法(进阶,自动化找最优)
新手用 ACF/PACF 可能判不准,进阶用 “AIC/BIC 准则”—— 遍历 p 和 q 的组合,选 AIC/BIC 最小的组合(值越小,模型越优)。
核心逻辑
- AIC(赤池信息准则):兼顾模型拟合度和复杂度,适合样本量大的情况;
- BIC(贝叶斯信息准则):对复杂模型惩罚更重,避免过度拟合,适合小样本;
- 遍历 p∈[0,5]、q∈[0,5](新手足够),计算每个组合的 AIC/BIC,选最小值对应的 p/q。
代码实操(自动化找最优 p/q)
from statsmodels.tsa.arima.model import ARIMA
# 拆分训练集(用前80%数据找最优参数)
train_size = int(len(series) * 0.8)
train = series[:train_size]
# 定义参数遍历范围(新手选0-5即可)
p_range = range(0, 6)
q_range = range(0, 6)
d = 1 # 已确定d=1
# 存储最优参数
best_aic = float('inf')
best_bic = float('inf')
best_params = (0, d, 0)
# 遍历所有p/q组合
print("===== 遍历p/q组合,找最优参数 =====")
for p in p_range:
for q in q_range:
try:
# 训练模型
model = ARIMA(train, order=(p, d, q))
result = model.fit()
# 记录AIC/BIC
aic = result.aic
bic = result.bic
# 打印当前组合
print(f"ARIMA({p},{d},{q}) → AIC: {aic:.2f}, BIC: {bic:.2f}")
# 更新最优参数
if aic < best_aic:
best_aic = aic
best_params = (p, d, q)
if bic < best_bic:
best_bic = bic
except:
# 部分组合可能报错,跳过
continue
# 输出最优参数
print("\n===== 最优参数结果 =====")
print(f"基于AIC最优的参数:ARIMA{best_params}(AIC={best_aic:.2f})")
print(f"基于BIC最优的参数:ARIMA{best_params}(BIC={best_bic:.2f})")
结果解读:
- 遍历后会发现,ARIMA (2,1,2) 的 AIC/BIC 值最小→ 验证了 ACF/PACF 图法的结论;
- 若遍历出其他最优值(比如 p=1,q=2),优先选 AIC/BIC 更小的组合。
三、新手避坑指南(选阶数最易犯的错)
- 过度差分(d 选太大):比如 d=3,会导致数据过度平稳,ACF 图在 lag=1 处过度负相关(值 <-0.5),模型预测能力下降;
- p/q 选太大:比如 p=10,q=10,模型复杂度过高,容易 “过拟合”(训练集预测准,测试集预测差);
- 只看 ACF/PACF 不验证:选完 p/q 后,一定要用测试集评估(看 MSE/RMSE),若误差大,微调 p/q(比如 p±1,q±1);
- 忽略数据特点:比如太阳黑子有 11 年周期,选 p/q 时可参考周期(比如 p=11),但新手先从小值试。
四、总结(核心关键点)

你可以把上述代码结合太阳黑子数据集运行,先手动用 ACF/PACF 选,再用自动化遍历验证,就能直观感受到 “最优参数” 的选择逻辑 —— 零基础不用死记理论,先动手试,试几次就知道怎么选了。
如何选择合适的差分阶数?
你想知道如何根据数据的特点,选择合适的差分类型(n 阶差分 / 季节性差分)和差分阶数(比如 d=1 还是 d=2),作为零基础学习者,我会用 “看病对症下药” 的思路,结合你熟悉的 AirPassengers 数据集,用最通俗的语言 + 可直接运行的代码,把 “选差分” 的步骤拆解得明明白白 —— 核心就是 “先找不平稳的原因,再选对应差分,最后验证效果”。
一、先明确核心逻辑:差分是 “对症下药”
数据不平稳就像人生病,差分是 “吃药”:
- 病因为 “趋势”(数据一直涨 / 跌,比如零花钱每月多 100)→ 吃 “n 阶差分药”;
- 病因为 “季节性”(数据固定周期波动,比如每年 7 月乘客多)→ 吃 “季节性差分药”;
- 病因是 “趋势 + 季节性”(比如 AirPassengers 既涨又有季节性)→ 两种药搭配吃;
- 关键:只吃到 “病好”(数据平稳)为止,别多吃(过度差分)。
二、选择合适差分的 4 个步骤(零基础无脑套用)
步骤 1:先诊断数据 “不平稳的病因”(可视化 + 简单统计)
先搞清楚数据不平稳是 “趋势导致的”“季节性导致的”,还是 “两者都有”,这是选差分的前提。
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller, kpss
# 中文显示设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 加载数据(还是用AirPassengers,新手最熟悉)
data = pd.read_csv(
'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv',
parse_dates=['Month'],
index_col='Month'
)
passengers = data['Passengers']
# 诊断工具1:画整体趋势图(看有没有趋势)
plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.plot(passengers, color='blue')
plt.title('整体趋势(看是否一直涨/跌)')
plt.grid(alpha=0.3)
# 诊断工具2:月度箱线图(看有没有季节性)
plt.subplot(1,2,2)
data['月份'] = data.index.month
data.boxplot(column='Passengers', by='月份', grid=False)
plt.title('月度分布(看季节性)')
plt.suptitle('') # 去掉默认标题
plt.tight_layout()
plt.show()
# 结论(AirPassengers):
# 1. 整体趋势图:一路向上 → 有“趋势型不平稳”;
# 2. 月度箱线图:7/8月乘客多,1/2月少 → 有“季节型不平稳”;
# → 需要同时处理趋势和季节性。
步骤 2:根据 “病因” 选差分类型(先选 “药的种类”)
| 数据不平稳原因 | 适用差分类型 | 举例(新手易理解) |
|---|---|---|
| 只有趋势(无季节性) | n 阶差分(d=1/2) | 每月零花钱:1000→1100→1200 |
| 只有季节性(无趋势) | 季节性差分(D=1,S = 周期) | 每月电费:夏天高、冬天低,但每年均值一样 |
| 趋势 + 季节性 | 先季节性差分,再 n 阶差分(或反过来) | AirPassengers 数据集 |
关键:确定季节性周期 S(新手必记):
- 月度数据(比如每月乘客数)→ S=12;
- 周度数据(比如每周销量)→ S=7;
- 日度数据(比如每日气温)→ S=365(年)或 S=7(周);
- 季度数据→ S=4。
步骤 3:确定差分阶数(再选 “药的剂量”)
阶数就是 “差分几次”,核心原则:从 0 开始试,1 阶优先,最多试到 2 阶,绝对不试 3 阶及以上(过度差分)。
子步骤 3.1:确定 n 阶差分的阶数(d)
操作逻辑:试 1 阶→检验平稳性→不平稳再试 2 阶→平稳就停。
# 定义平稳性检验函数(复用之前的,新手直接用)
def check_stationary(series):
"""同时用ADF和KPSS检验,双重验证"""
# ADF检验(假设不平稳,p<0.05则平稳)
adf_result = adfuller(series)
adf_p = adf_result[1]
# KPSS检验(假设平稳,p>0.05则平稳)
kpss_result = kpss(series, regression='c')
kpss_p = kpss_result[1]
print(f"ADF p值:{adf_p:.4f} | KPSS p值:{kpss_p:.4f}")
if adf_p < 0.05 and kpss_p > 0.05:
print("→ 数据平稳 ✅")
return True
else:
print("→ 数据不平稳 ❌")
return False
# 试1阶差分(处理趋势)
diff1 = passengers.diff().dropna()
print("【1阶差分后平稳性】")
is_stationary_diff1 = check_stationary(diff1)
# 如果1阶不平稳,试2阶差分(极少需要)
if not is_stationary_diff1:
diff2 = diff1.diff().dropna()
print("\n【2阶差分后平稳性】")
check_stationary(diff2)
# 结果(AirPassengers):
# 1阶差分后ADF p≈0.05(临界),KPSS p<0.05 → 仍不平稳(因为还有季节性)
子步骤 3.2:确定季节性差分的阶数(D)
操作逻辑:先做 1 阶季节性差分(当前值 - S 期前的值)→ 检验平稳性→不平稳再试 2 阶(几乎不用)。
# 1阶季节性差分(S=12,月度数据)
season_diff1 = passengers.diff(12).dropna()
print("\n【1阶季节性差分后平稳性】")
is_stationary_season = check_stationary(season_diff1)
# 结果(AirPassengers):
# 1阶季节性差分后,ADF p≈0.01(<0.05),KPSS p≈0.1(>0.05)→ 比1阶差分更平稳,但还有轻微趋势
子步骤 3.3:趋势 + 季节性的组合差分(核心实操)
如果单独的 n 阶或季节性差分都不平稳,就 “组合使用”:
# 方案1:先季节性差分(1阶),再1阶差分(处理剩余趋势)
combo_diff = season_diff1.diff().dropna()
print("\n【1阶季节性差分 + 1阶差分后平稳性】")
is_stationary_combo = check_stationary(combo_diff)
# 可视化组合差分后的结果(验证)
plt.figure(figsize=(10, 4))
plt.plot(combo_diff, color='green')
plt.title('1阶季节性差分+1阶差分后的数据')
plt.grid(alpha=0.3)
plt.show()
# 结果:
# 组合差分后ADF p<<0.05,KPSS p>0.05 → 完全平稳 ✅
步骤 4:避免 “过度差分”(新手最易踩的坑)
过度差分就是 “药吃多了”,比如明明 1 阶差分就平稳,却试了 2 阶,会导致:
- 数据丢失有用信息(比如趋势、季节性的规律);
- 差分后数据的方差变小,模型预测能力下降。
如何判断过度差分?
- 差分后数据的自相关系数(ACF)在 lag=1 处 “过度负相关”(比如 ACF 值 <-0.5);
- 差分后数据的均值≈0,且波动极小(比如所有值都在 0 附近)。
# 演示过度差分(AirPassengers试2阶季节性+2阶差分)
over_diff = passengers.diff(12).diff().diff().dropna()
print("\n【过度差分后平稳性】")
check_stationary(over_diff)
# 看ACF图判断过度差分
from statsmodels.graphics.tsaplots import plot_acf
plt.figure(figsize=(10, 4))
plot_acf(over_diff, lags=10, ax=plt.gca())
plt.title('过度差分后ACF图(lag=1过度负相关)')
plt.show()
# 结果:
# 过度差分后虽然平稳,但ACF在lag=1处≈-0.8(过度负相关)→ 不可用
三、不同场景的差分选择示例(新手对照表)
| 数据特点 | 差分选择方案 | 举例 |
|---|---|---|
| 无趋势、无季节性(平稳) | 不用差分(d=0,D=0) | 随机波动的每日股价(短期) |
| 只有趋势(无季节性) | 1 阶差分(d=1) | 每月零花钱稳步上涨 |
| 只有季节性(无趋势) | 1 阶季节性差分(D=1,S=12) | 每月电费(夏高冬低,均值不变) |
| 趋势 + 季节性 | 1 阶季节性差分 + 1 阶差分 | AirPassengers 数据集 |
四、总结(核心关键点)
- 选差分的核心逻辑:先诊断不平稳的原因(趋势 / 季节性)→ 选对应差分类型→ 从 1 阶开始试→ 平稳就停,最多试 2 阶;
- 优先级:1 阶差分 / 1 阶季节性差分优先,组合差分次之,绝对避免 3 阶及以上;
- 验证标准:差分后 ADF p<0.05 且 KPSS p>0.05,可视化看数据无明显趋势 / 季节性,且无过度负相关(避免过度差分)。
你可以把上面的代码逐行运行,对比 “1 阶差分、1 阶季节性差分、组合差分、过度差分” 的结果,就能直观感受到 “合适的差分” 是什么样的 —— 零基础不用死记规则,先动手试,试几次就知道怎么选了。
除了ARIMA和SARIMA,还有哪些常用的时序预测模型?
除了 ARIMA 和 SARIMA 这两类经典统计模型,常用的时序预测模型还可以分为 传统统计模型、机器学习模型、深度学习模型 三大类。我会用通俗易懂的比喻 + 适配 Mac 系统的代码 + 清晰的适用场景,帮你逐个理解,零基础也能快速上手。
核心分类逻辑
- 小数据 + 明显趋势 / 季节性 → 传统统计模型(简单易解释)
- 中等数据 + 多特征(比如天气、价格) → 机器学习模型(需要做特征工程)
- 大数据 + 长序列 + 复杂规律 → 深度学习模型(自动提取特征,预测精度高)
一、传统统计模型(简单好用,适合小数据)
这类模型和 ARIMA 一样,基于统计规律,不用复杂的特征工程,新手优先学。
1. 指数平滑法(代表:Holt-Winters 模型)
通俗原理
就像给近期数据 “加更高权重” 的加权平均:昨天的天气比上周的天气对今天的影响更大,越近的数据越重要。
- 简单指数平滑:适合无趋势、无季节性的数据(比如随机波动的股价);
- Holt 双指数平滑:适合有趋势、无季节性的数据(比如每月零花钱稳步上涨);
- Holt-Winters 三指数平滑:适合有趋势 + 有季节性的数据(比如 AirPassengers、太阳黑子),直接对标 SARIMA。
适用场景
小样本时序数据(比如几十到几百条)、趋势 + 季节性明显,且需要高解释性的场景(比如商业报表分析)。
Mac 适配代码(太阳黑子数据集为例)
# 导入库+Mac中文适配
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.holtwinters import ExponentialSmoothing
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 加载太阳黑子数据
from statsmodels.datasets import sunspots
data = sunspots.load_pandas().data
data['date'] = pd.to_datetime(data['YEAR'].astype(int).astype(str) + '-01-01')
data = data.set_index('date')[['SUNACTIVITY']]
data.columns = ['sunspots']
series = data['sunspots']
# 拆分训练集和测试集(8:2)
train_size = int(len(series) * 0.8)
train, test = series[:train_size], series[train_size:]
# 训练Holt-Winters模型
# trend='add':加法趋势;seasonal='add':加法季节性;seasonal_periods=11(太阳黑子11年周期)
model = ExponentialSmoothing(
train,
trend='add',
seasonal='add',
seasonal_periods=11 # 关键:设置季节周期
)
result = model.fit()
# 预测测试集
pred = result.predict(start=len(train), end=len(train)+len(test)-1)
# 可视化结果
plt.figure(figsize=(12, 6))
plt.plot(train, label='训练集', color='darkblue')
plt.plot(test, label='测试集(实际值)', color='green')
plt.plot(pred, label='预测值', color='red', linestyle='--')
plt.title('Holt-Winters 太阳黑子数量预测')
plt.xlabel('时间')
plt.ylabel('太阳黑子数量')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 优缺点总结
print("✅ 优点:简单易解释,小数据效果好,无需复杂参数调优")
print("❌ 缺点:不适合复杂长序列,多变量数据效果差")
2. VAR 模型(向量自回归模型)
通俗原理
ARIMA 是单变量模型(只预测一列数据),而 VAR 是多变量模型,适合 “多个变量互相影响” 的场景。比如:预测 “销量” 时,同时考虑 “价格”“广告投入”“天气”,VAR 会建模这些变量之间的互相影响关系。
适用场景
多变量时序数据(比如同时预测销量、价格、库存),变量之间存在明显的相互关联。
Mac 适配代码(模拟多变量数据)
import numpy as np
from statsmodels.tsa.vector_ar.var_model import VAR
# 模拟多变量时序数据:3个变量(比如销量、价格、广告投入)
np.random.seed(42)
n = 100
t = np.arange(n)
# 变量1:销量(有趋势)
sales = 100 + 2*t + np.random.normal(0, 5, n)
# 变量2:价格(和销量负相关)
price = 50 - 0.5*t + np.random.normal(0, 3, n)
# 变量3:广告投入(和销量正相关)
ad = 10 + 0.8*t + np.random.normal(0, 2, n)
# 构建DataFrame
df = pd.DataFrame({
'sales': sales,
'price': price,
'ad': ad
}, index=pd.date_range('2020-01-01', periods=n, freq='M'))
# 拆分训练集和测试集
train_size = int(n * 0.8)
train_df, test_df = df[:train_size], df[train_size:]
# 训练VAR模型
model = VAR(train_df)
# 选择最优滞后阶数(基于AIC准则)
best_order = model.select_order(maxlags=10)
print(f"最优滞后阶数:{best_order.aic}")
var_model = model.fit(best_order.aic)
# 预测测试集
pred_df = var_model.forecast(train_df.values, steps=len(test_df))
pred_df = pd.DataFrame(pred_df, columns=df.columns, index=test_df.index)
# 可视化销量预测结果
plt.figure(figsize=(10, 4))
plt.plot(df['sales'], label='历史销量', color='blue')
plt.plot(pred_df['sales'], label='预测销量', color='red', linestyle='--')
plt.title('VAR模型 销量预测(多变量)')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 优缺点总结
print("✅ 优点:支持多变量预测,能捕捉变量间的关联")
print("❌ 缺点:变量太多时效果差,需要平稳数据")
二、机器学习模型(中等数据,需要特征工程)
这类模型把时序预测问题转化为回归问题,通过构造 “时序特征” 来训练模型,适合有一定数据量且能提取特征的场景。
代表模型:XGBoost/LightGBM/Random Forest
通俗原理
把 “过去的时序数据” 转化为模型能理解的特征,比如:
- 滞后特征:用前 1 期、前 2 期、前 7 期的数据作为特征;
- 滚动统计特征:过去 7 天的均值、最大值、标准差;
- 时间特征:月份、季度、是否节假日。然后用树模型(XGBoost 等)训练,预测未来值。
适用场景
中等数据量(几百到几万条)、多特征融合(比如时序数据 + 外部数据)、需要高精度且能接受一定解释性损失的场景。
Mac 适配代码(XGBoost 时序预测)
import xgboost as xgb
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
# 加载太阳黑子数据
series = data['sunspots']
# 核心步骤:构造时序特征
def create_time_features(series, lags=[1, 2, 3, 6, 12]):
df = series.to_frame(name='target')
# 1. 滞后特征:前1/2/3/6/12期的数据
for lag in lags:
df[f'lag_{lag}'] = df['target'].shift(lag)
# 2. 滚动统计特征:过去3期的均值和标准差
df['roll_mean_3'] = df['target'].rolling(window=3).mean().shift(1)
df['roll_std_3'] = df['target'].rolling(window=3).std().shift(1)
# 3. 时间特征:年份、月份
df['year'] = df.index.year
df['month'] = df.index.month
# 去掉空值
df = df.dropna()
return df
# 构造特征
df_features = create_time_features(series)
X = df_features.drop('target', axis=1) # 特征
y = df_features['target'] # 目标变量
# 拆分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # 时序数据不能shuffle!
# 训练XGBoost模型
model = xgb.XGBRegressor(
n_estimators=100,
learning_rate=0.1,
random_state=42
)
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
# 可视化结果
plt.figure(figsize=(12, 6))
plt.plot(y_train.index, y_train, label='训练集', color='blue')
plt.plot(y_test.index, y_test, label='测试集(实际值)', color='green')
plt.plot(y_test.index, y_pred, label='预测值', color='red', linestyle='--')
plt.title('XGBoost 太阳黑子数量预测')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 评估模型
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"测试集RMSE:{rmse:.2f}")
# 优缺点总结
print("✅ 优点:支持多特征,精度高,对非线性规律捕捉好")
print("❌ 缺点:需要手动构造特征,对长序列预测效果差")
关键注意事项:时序数据拆分时绝对不能 shuffle(打乱顺序),否则会泄露未来信息!
三、深度学习模型(大数据长序列,自动提取特征)
这类模型基于神经网络,能自动学习时序数据的深层规律,不用手动构造复杂特征,适合大数据、长序列的复杂场景。
1. LSTM/GRU(长短期记忆网络 / 门控循环单元)
通俗原理
传统的循环神经网络(RNN)容易 “忘记” 长期信息(比如预测第 100 期数据时,记不住第 1 期的信息),而 LSTM 通过 “门机制”(输入门、遗忘门、输出门),可以选择性地记住长期信息、忘记无用信息,特别适合长序列预测。GRU 是 LSTM 的简化版,参数更少,训练更快。
适用场景
大数据量(几万到几百万条)、长序列(比如预测未来 30 天的气温)、复杂非线性规律。
Mac 适配代码(PyTorch 实现 LSTM 预测)
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# Mac 下自动选择设备:有GPU用GPU,没有用CPU
device = torch.device('mps' if torch.backends.mps.is_available() else 'cpu')
print(f"使用设备:{device}")
# 数据预处理:标准化+构造序列
series = data['sunspots'].values
# 标准化(深度学习必须做,否则模型不收敛)
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
series_scaled = scaler.fit_transform(series.reshape(-1, 1)).flatten()
# 构造序列数据:用前seq_len个数据预测下1个数据
seq_len = 12 # 用前12期预测第13期
X, y = [], []
for i in range(len(series_scaled) - seq_len):
X.append(series_scaled[i:i+seq_len])
y.append(series_scaled[i+seq_len])
X = np.array(X).reshape(-1, seq_len, 1) # 形状:(样本数, 序列长度, 特征数)
y = np.array(y).reshape(-1, 1)
# 转为Tensor并拆分训练集/测试集
X_tensor = torch.tensor(X, dtype=torch.float32).to(device)
y_tensor = torch.tensor(y, dtype=torch.float32).to(device)
train_size = int(0.8 * len(X_tensor))
X_train, X_test = X_tensor[:train_size], X_tensor[train_size:]
y_train, y_test = y_tensor[:train_size], y_tensor[train_size:]
# 构建LSTM模型
class LSTMModel(nn.Module):
def __init__(self, input_size=1, hidden_size=64, output_size=1):
super().__init__()
self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
lstm_out, _ = self.lstm(x)
out = self.fc(lstm_out[:, -1, :]) # 取最后一个时间步的输出
return out
model = LSTMModel().to(device)
criterion = nn.MSELoss() # 损失函数:均方误差
optimizer = optim.Adam(model.parameters(), lr=0.001) # 优化器
# 训练模型
batch_size = 32
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)
epochs = 50
for epoch in range(epochs):
model.train()
total_loss = 0
for batch_X, batch_y in train_loader:
optimizer.zero_grad()
pred = model(batch_X)
loss = criterion(pred, batch_y)
loss.backward()
optimizer.step()
total_loss += loss.item()
if (epoch+1) % 10 == 0:
print(f"Epoch [{epoch+1}/{epochs}], Loss: {total_loss/len(train_loader):.4f}")
# 预测
model.eval()
with torch.no_grad():
y_pred_tensor = model(X_test)
# 反标准化,还原真实值
y_pred = scaler.inverse_transform(y_pred_tensor.cpu().numpy())
y_test_true = scaler.inverse_transform(y_test.cpu().numpy())
# 可视化结果
plt.figure(figsize=(12, 6))
plt.plot(range(len(y_train)), scaler.inverse_transform(y_train.cpu().numpy()), label='训练集', color='blue')
plt.plot(range(len(y_train), len(y_train)+len(y_test)), y_test_true, label='测试集(实际值)', color='green')
plt.plot(range(len(y_train), len(y_train)+len(y_test)), y_pred, label='预测值', color='red', linestyle='--')
plt.title('LSTM 太阳黑子数量预测')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 优缺点总结
print("✅ 优点:自动提取特征,长序列预测效果好,适合复杂规律")
print("❌ 缺点:需要大数据量,训练慢,解释性差")
2. 其他深度学习模型
- TCN(时间卷积网络):用卷积代替循环,训练速度比 LSTM 快,适合长序列;
- Transformer(比如 Temporal Fusion Transformer, TFT):基于注意力机制,能捕捉长距离依赖,是目前时序预测的 SOTA 模型之一;
- Prophet:Facebook 开源的模型,结合了统计和机器学习,无需专业知识,调参简单。
四、常用模型选择对照表(新手直接套用)
| 数据特点 | 推荐模型 | 核心优势 |
|---|---|---|
| 小数据 + 趋势 / 季节性 | Holt-Winters > ARIMA | 简单易解释,无需复杂调参 |
| 多变量 + 变量互相关联 | VAR 模型 | 捕捉变量间的关联关系 |
| 中等数据 + 多特征融合 | XGBoost/LightGBM | 精度高,支持非线性规律 |
| 大数据 + 长序列 + 复杂规律 | LSTM/Transformer | 自动提取特征,长序列效果好 |
| 业务导向 + 快速上手 | Prophet(Facebook 开源) | 调参简单,适合业务人员 |
五、Mac 系统运行注意事项
- 深度学习设备:Mac 搭载 Apple Silicon 芯片(M1/M2/M3)的可以用
mps加速训练,比 CPU 快很多; - 库安装:用
pip3 install xgboost lightgbm torch statsmodels scikit-learn安装所有依赖; - 内存问题:大数据训练时,减小 batch_size 避免内存溢出。
这些模型你可以根据自己的数据情况选择,新手建议先从 Holt-Winters 和 XGBoost 入手,容易出效果,再逐步学习深度学习模型。
作业:对太阳黑子数量数据集用 arima 完成流程
使用 Mac OS 系统,想要基于今天学的时序建模全流程,对太阳黑子数量数据集完成 ARIMA 模型的实战项目,我会为你提供适配 Mac 系统的详细步骤 + 可直接运行的代码,每一步都标注 Mac 系统的注意事项,确保你能顺利跑通。
一、先明确太阳黑子数据集特点(提前了解)
太阳黑子数据集记录了每月太阳黑子的数量,核心特征:
- 单变量时序数据,时间跨度长(1749-2018 年);
- 有周期性波动(约 11 年一个周期),无明显长期趋势;
- 数据整体不平稳,需要差分处理。
二、Mac OS 环境准备(第一步必做)
Mac 系统默认带 Python,但需要安装必备库,打开「终端」执行以下命令(复制粘贴即可):
# 安装核心库(pandas/numpy/matplotlib/statsmodels/sklearn)
pip3 install pandas numpy matplotlib statsmodels scikit-learn
# 注意:Mac下Python3的包管理用pip3(避免和Python2混淆),如果提示权限问题,加 --user # pip3 install --user pandas numpy matplotlib statsmodels scikit-learn

三、ARIMA 建模全流程(分 8 步,代码 + 解释)
步骤 1:导入库 + 适配 Mac 中文显示
Mac 系统的中文字体和 Windows 不同,这里专门适配,避免画图乱码:
# 导入核心库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller, kpss
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error, mean_absolute_error
import warnings
warnings.filterwarnings('ignore') # 屏蔽无关警告(新手更清爽)
# ===== Mac系统专属:适配中文显示 =====
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # Mac自带的中文字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
步骤 2:数据获取(太阳黑子数据集在线获取,无需本地文件)
# 加载太阳黑子数据集(经典数据集,在线获取)
# 数据来源:statsmodels内置,或在线CSV(两种方式都给,选一种即可)
# 方式1:statsmodels内置(推荐,无需联网也能加载)
from statsmodels.datasets import sunspots
data = sunspots.load_pandas().data # 加载数据
# 处理时间索引:Year是年份,补充月份为1月,转为时间格式
data['date'] = pd.to_datetime(data['YEAR'].astype(int).astype(str) + '-01-01')
data = data.set_index('date') # 设为时间索引
data = data[['SUNACTIVITY']] # 只保留太阳黑子数量列
data.columns = ['sunspots'] # 列名简化
# 方式2:在线CSV(备用,如果方式1报错)
# data = pd.read_csv(
# 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/monthly-sunspots.csv',
# parse_dates=['Month'],
# index_col='Month'
# )
# data.columns = ['sunspots'] # 列名简化
# 数据预览
print("===== 数据前5行 =====")
print(data.head())
print("\n===== 数据基础信息 =====")
print(f"数据时间范围:{data.index.min()} 到 {data.index.max()}")
print(f"数据维度:{data.shape}") # (309, 1) 或 (2820,1),取决于数据源,都不影响流程
print(f"缺失值数量:{data.isnull().sum()[0]}") # 无缺失值
步骤 3:数据探索(EDA,找规律 + 检验平稳性)
# 3.1 可视化整体趋势(看周期性)
plt.figure(figsize=(12, 8))
# 子图1:整体趋势
plt.subplot(2, 2, 1)
plt.plot(data['sunspots'], color='darkblue')
plt.title('太阳黑子数量整体趋势(1749-2018)')
plt.xlabel('时间')
plt.ylabel('太阳黑子数量')
plt.grid(alpha=0.3)
# 子图2:滚动均值+标准差(判断平稳性)
plt.subplot(2, 2, 2)
roll_mean = data['sunspots'].rolling(window=12).mean() # 12个月滚动均值
roll_std = data['sunspots'].rolling(window=12).std() # 12个月滚动标准差
plt.plot(data['sunspots'], label='原始数据', color='darkblue')
plt.plot(roll_mean, label='12月滚动均值', color='red')
plt.plot(roll_std, label='12月滚动标准差', color='green')
plt.title('滚动均值+标准差')
plt.legend()
plt.grid(alpha=0.3)
# 子图3:ACF图(自相关,看周期性)
plt.subplot(2, 2, 3)
plot_acf(data['sunspots'], lags=60, ax=plt.gca()) # lags=60,看5年的自相关
plt.title('ACF图(原始数据)')
plt.grid(alpha=0.3)
# 子图4:PACF图(偏自相关)
plt.subplot(2, 2, 4)
plot_pacf(data['sunspots'], lags=60, ax=plt.gca(), method='ywm')
plt.title('PACF图(原始数据)')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
# 3.2 平稳性检验(ADF+KPSS)
def check_stationary(series):
"""Mac系统下的平稳性检验函数,输出清晰结果"""
# ADF检验
adf_result = adfuller(series)
adf_p = adf_result[1]
# KPSS检验
kpss_result = kpss(series, regression='c')
kpss_p = kpss_result[1]
print("===== 平稳性检验结果 =====")
print(f"ADF p值:{adf_p:.4f}(<0.05 则平稳)")
print(f"KPSS p值:{kpss_p:.4f}(>0.05 则平稳)")
if adf_p < 0.05 and kpss_p > 0.05:
print("→ 数据平稳 ✅")
return True
else:
print("→ 数据不平稳 ❌")
return False
# 检验原始数据
print("\n【原始数据平稳性】")
is_stationary = check_stationary(data['sunspots'])
步骤 4:数据预处理(选择合适的差分)
太阳黑子数据无明显趋势,但有周期性,先试 1 阶差分:
# 4.1 1阶差分(处理不平稳)
data_diff1 = data['sunspots'].diff().dropna()
# 4.2 检验差分后平稳性
print("\n【1阶差分后平稳性】")
is_stationary_diff1 = check_stationary(data_diff1)
# 4.3 可视化差分后数据
plt.figure(figsize=(10, 4))
plt.plot(data_diff1, color='darkgreen')
plt.title('太阳黑子数据1阶差分后')
plt.xlabel('时间')
plt.ylabel('差分后数量')
plt.grid(alpha=0.3)
plt.show()
# 4.4 差分后ACF/PACF(确定p,q)
plt.figure(figsize=(10, 4))
plt.subplot(1,2,1)
plot_acf(data_diff1, lags=30, ax=plt.gca())
plt.title('1阶差分后ACF图')
plt.subplot(1,2,2)
plot_pacf(data_diff1, lags=30, ax=plt.gca(), method='ywm')
plt.title('1阶差分后PACF图')
plt.tight_layout()
plt.show()
# 差分后分析结论:
# 1阶差分后ADF p<0.05,KPSS p>0.05 → 平稳;
# ACF在lag=10左右衰减,PACF在lag=2左右截断 → 初步选p=2, d=1, q=10(或简化为p=2, d=1, q=2)
步骤 5:拆分训练集 + 测试集(Mac 系统下无路径问题)
# 按8:2拆分(前80%训练,后20%测试)
train_size = int(len(data) * 0.8)
train = data['sunspots'][:train_size]
test = data['sunspots'][train_size:]
print(f"\n===== 数据集拆分 =====")
print(f"训练集长度:{len(train)}")
print(f"测试集长度:{len(test)}")
print(f"测试集时间范围:{test.index.min()} 到 {test.index.max()}")
步骤 6:训练 ARIMA 模型(Mac 系统兼容)
# 6.1 定义并训练ARIMA模型(p=2, d=1, q=2,新手友好版)
# 注:如果想更精准,可试p=2, d=1, q=10,Mac系统计算稍慢但能运行
model = ARIMA(train, order=(2, 1, 2)) # (p,d,q)=(2,1,2)
result = model.fit()
# 6.2 输出模型摘要(Mac下正常显示)
print("\n===== ARIMA模型摘要 =====")
print(result.summary())
步骤 7:模型评估(Mac 下计算评估指标)
# 7.1 预测测试集
pred = result.predict(start=len(train), end=len(train)+len(test)-1, typ='levels')
# typ='levels':预测原始尺度,而非差分尺度
# 7.2 可视化预测结果
plt.figure(figsize=(12, 6))
plt.plot(train, label='训练集', color='darkblue')
plt.plot(test, label='测试集(实际值)', color='green')
plt.plot(pred, label='预测值', color='red', linestyle='--')
plt.title('ARIMA(2,1,2) 太阳黑子数量预测结果')
plt.xlabel('时间')
plt.ylabel('太阳黑子数量')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 7.3 计算评估指标(MSE, MAE, RMSE)
mse = mean_squared_error(test, pred)
mae = mean_absolute_error(test, pred)
rmse = np.sqrt(mse)
print("\n===== 模型评估指标 =====")
print(f"均方误差(MSE):{mse:.2f}(越小越好)")
print(f"平均绝对误差(MAE):{mae:.2f}(越小越好)")
print(f"均方根误差(RMSE):{rmse:.2f}(越小越好)")
步骤 8:未来预测(Mac 下无兼容问题)
# 8.1 预测未来10年(120个月)的太阳黑子数量
forecast_steps = 120 # 预测未来120个月(10年)
forecast = result.get_forecast(steps=forecast_steps)
forecast_mean = forecast.predicted_mean # 预测均值
forecast_ci = forecast.conf_int() # 95%置信区间
# 8.2 可视化未来预测
plt.figure(figsize=(12, 6))
# 历史数据
plt.plot(data['sunspots'], label='历史数据', color='darkblue')
# 预测值
plt.plot(forecast_mean.index, forecast_mean, label='未来预测值', color='red')
# 置信区间
plt.fill_between(forecast_ci.index,
forecast_ci.iloc[:, 0],
forecast_ci.iloc[:, 1],
color='pink', alpha=0.3, label='95%置信区间')
plt.title('太阳黑子数量历史数据+未来10年预测')
plt.xlabel('时间')
plt.ylabel('太阳黑子数量')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# 8.3 输出未来预测的前10个值
print("\n===== 未来10个月太阳黑子数量预测 =====")
print(forecast_mean.head(10))
四、Mac 系统运行注意事项(避坑指南)
- 字体问题:如果中文还是乱码,把
Arial Unicode MS换成Heiti TC(Mac 繁体黑体)或PingFang SC(苹方); - 库安装失败:如果
statsmodels安装报错,先安装依赖: - Python 版本:Mac 下如果输入
python3才是 Python3,python是 Python2,运行代码时用: - 内存问题:太阳黑子数据集不大,Mac 低配也能运行,无需担心卡顿。


五、总结(核心关键点)
- 流程完整性:从数据获取→探索→预处理→建模→评估→预测,覆盖了时序建模全流程;
- Mac 适配:专门调整了中文字体、库安装命令、Python 版本适配,确保你能直接运行;
- 参数选择:太阳黑子数据 1 阶差分即可平稳,ARIMA 参数选 (2,1,2)(新手友好),也可尝试 (2,1,10) 提升精度;
- 核心指标:通过 MSE/MAE/RMSE 评估模型,置信区间能反映预测的不确定性。
你可以把上述代码复制到 Mac 的文本编辑器(比如 VS Code、PyCharm,或自带的 TextEdit),保存为sunspots_arima.py,然后在终端执行python3 sunspots_arima.py即可运行 —— 每一步都有输出,你可以对照输出理解模型的效果,新手建议逐段运行,看每一步的结果。
更多推荐

所有评论(0)