当前位置: 首页 > java >正文

DAY 58 经典时序预测模型2

知识点回顾:

  1. 时序建模的流程
  2. 时序任务经典单变量数据集
  3. ARIMA(p,d,q)模型实战
  4. SARIMA摘要图的理解
  5. 处理不平稳的2种差分
    1. n阶差分---处理趋势
    2. 季节性差分---处理季节性

昨天我们掌握了AR, MA, 和 ARMA 模型,它们是处理平稳时间序列的利器。但现实世界的数据,比如股票价格、公司销售额,往往带有明显的趋势性或季节性,它们是不平稳的。今天,我们就来学习ARIMA模型,它正是为了解决这个问题而生的。

他进一步引入差分来解决不平稳问题

差分是使数据平稳化的关键步骤。

一阶差分: 就是序列中每个点减去它前一个点的值。
diff(t) = value(t) - value(t-1)
这通常可以消除数据中的线性趋势。

二阶差分: 对一阶差分后的结果再做一次差分。
diff2(t) = diff(t) - diff(t-1)
这可以消除数据中的曲线趋势(比如抛物线趋势)。

ARIMA建模的完整流程

建立一个ARIMA模型,通常遵循以下步骤:

  1. 数据可视化:观察原始时间序列图,判断是否存在趋势或季节性。
  2. 平稳性检验:
    • 对原始序列进行ADF检验。
    • 如果p值 > 0.05,说明序列非平稳,需要进行差分。
  3. 确定差分次数 d:
    • 进行一阶差分,然后再次进行ADF检验。
    • 如果平稳了,则 d=1。否则,继续差分,直到平稳。
  4. 确定 p 和 q:
    • 对差分后的平稳序列绘制ACF和PACF图。
    • 根据昨天学习的规则(PACF定p,ACF定q)来选择p和q的值。
  5. 建立并训练ARIMA(p, d, q)模型。
  6. 模型评估与诊断:查看模型的摘要信息,检查残差是否为白噪声。
  7. 进行预测

一、 时序任务经典数据集

就像机器学习有鸢尾花、手写数字、波士顿房价这些“标准”数据集一样,时间序列分析领域也有一些“名人堂”成员。

这些经典数据集之所以经典,是因为它们各自清晰地展示了时间序列中一种或多种核心特征(如趋势、季节性、周期性等),非常适合用来教学和检验模型。

下面介绍几个最著名、最常用的单变量时间序列经典数据集,并附上获取它们的代码。

1.1 国际航空乘客数量 (Airline Passengers)

  • 数据描述: 1949年到1960年每月国际航空公司的总乘客数量。
  • 强趋势性: 随着时间推移,乘客数量有非常明显的线性增长趋势。
  • 强季节性: 每年都有一个固定的模式,夏季(6-8月)是高峰,冬季是低谷。
  • 变化的方差: 越到后期,季节性波动的幅度越大,这是一种异方差性。
import pandas as pd
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv'
df_air = pd.read_csv(url, header=0, index_col=0, parse_dates=True)
df_air.head()# 这是一种直接使用 URL 在线读取数据集的方式,代码通过pd.read_csv(url)直接从网络 URL 读取数据,Pandas 会自动处理网络请求并加载数据到内存中,属于 “在线读取” 方式。df_air.plot()# <matplotlib.axes._subplots.AxesSubplot at 0x29eb6ea3e80>
Passengers
Month
1949-01-01112
1949-02-01118
1949-03-01132
1949-04-01129
1949-05-01121

这里没有导入matplotlib仍然可以画图,是因为当调用df.plot()时,Pandas 会隐式导入 Matplotlib(如果尚未导入),并使用其绘图接口生成图表。对于简单的可视化需求,无需显式导入 Matplotlib,减少代码量。这里省略了plt.title(‘xxx’)和plt.show()等

1.2 太阳黑子数量 (Sunspots)

  • 数据描述: 每年观测到的太阳黑子数量。
  • 无明显趋势: 长期来看,数据没有持续的上升或下降趋势。
  • 强周期性 (Cyclical): 数据呈现非常明显的周期性波动,大约每11年一个周期。注意,这与“季节性”不同,季节性周期是固定的(如12个月),而这里的周期长度是近似的。
  • 相对平稳: 经过检验,数据通常被认为是平稳或近似平稳的。
from statsmodels.datasets import sunspots
df_sun = sunspots.load_pandas().data['SUNACTIVITY']
df_sun.head()#  0     5.0
#  1    11.0
#  2    16.0
#  3    23.0
#  4    36.0
#  Name: SUNACTIVITY, dtype: float64df_sun.plot()# <matplotlib.axes._subplots.AxesSubplot at 0x29eb29bde80>

非常适合用来理解ARMA模型。由于数据本身比较平稳,不需要差分,可以专注于用ACF和PACF图来确定 p 和 q 的值。

1.3 加州每日女性出生数量 (Daily Female Births)

  • 数据描述: 1959年,美国加州每一天的女性新生儿数量。
  • 无趋势、无季节性: 数据看起来像随机波动,没有明显的趋势或可预测的季节模式。
  • 平稳性: ADF检验通常会显示该序列是平稳的。
import pandas as pd
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-total-female-births.csv'
df_births = pd.read_csv(url, header=0, index_col=0, parse_dates=True)
# df_births.plot()
df_births.plot()# <matplotlib.axes._subplots.AxesSubplot at 0x29eb6fede80>

二、时间序列任务实战

进阶: 使用 太阳黑子 数据,让学员练习用ACF/PACF为ARMA模型定阶。
核心: 用 国际航空乘客 数据,系统地讲解从非平稳到平稳(差分),再到建立ARIMA和SARIMA的全过程。

2.1 加州每日女性预测

# 导入必要的库
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA# 设置matplotlib以正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 加载数据
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-total-female-births.csv'
df = pd.read_csv(url, header=0, index_col=0, parse_dates=True)
df.columns = ['Births']
ts_data = df['Births']print("--- 原始数据预览 ---")
print(ts_data.head())# 绘制时序图
plt.figure(figsize=(14, 7))
plt.plot(ts_data)
plt.title('1959年加州每日女性出生数量')
plt.xlabel('日期')
plt.ylabel('出生数量')
plt.show()#--- 原始数据预览 ---
#  Date
#  1959-01-01    35
#  1959-01-02    32
#  1959-01-03    30
#  1959-01-04    31
#  1959-01-05    44
#  Name: Births, dtype: int64

从图上看,数据点在一个稳定的水平线(大约40)上下随机波动。没有明显的上升或下降趋势,也没有看到以周或月为单位的固定模式。这给我们一个初步印象:这个序列很可能是平稳的。

直觉需要被验证。我们使用ADF检验来科学地判断其平稳性。

def adf_test(timeseries):print('--- ADF检验结果 ---')# H0: 序列非平稳; H1: 序列平稳result = adfuller(timeseries)print(f'ADF Statistic: {result[0]}')print(f'p-value: {result[1]}') # 重点关注这个值if result[1] <= 0.05:print("结论: 成功拒绝原假设,序列是平稳的。")else:print("结论: 未能拒绝原假设,序列是非平稳的。")adf_test(ts_data)#  --- ADF检验结果 ---
#  ADF Statistic: -4.808291253559765
#  p-value: 5.2434129901498554e-05
#  结论: 成功拒绝原假设,序列是平稳的。

既然数据是平稳的,我们就不需要对它进行差分来“铲平”它。这意味着:差分次数 d = 0

我们现在只需要确定 p 和 q。模型将是 ARIMA(p, 0, q),这其实就是我们昨天学的 ARMA(p, q) 模型。

# 因为数据是平稳的,我们直接对原始数据绘制ACF和PACF
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))plot_acf(ts_data, ax=ax1, lags=40)
ax1.set_title('自相关函数 (ACF)')plot_pacf(ts_data, ax=ax2, lags=40)
ax2.set_title('偏自相关函数 (PACF)')plt.tight_layout()
plt.show()

  • PACF图: 在滞后2阶之后,几乎所有的相关性都落入了蓝色置信区间内,我们可以认为它在 滞后2阶后截尾。这强烈暗示 p=2。
  • ACF图: 呈现出拖尾的模式(缓慢下降)。

所以,我们的候选模型是 ARIMA(2, 0, 0)。

import warnings
warnings.filterwarnings("ignore")
# 建立ARIMA(2, 0, 0)模型
model = ARIMA(ts_data, order=(2, 0, 0))
arima_result = model.fit()# 打印模型摘要
print(arima_result.summary())# 让我们预测未来30天
forecast_steps = 30
forecast = arima_result.get_forecast(steps=forecast_steps)
pred_mean = forecast.predicted_mean
conf_int = forecast.conf_int()# 绘制结果
plt.figure(figsize=(14, 7))
plt.plot(ts_data, label='原始数据')
# 绘制模型在历史数据上的拟合值
plt.plot(arima_result.fittedvalues, color='orange', label='模型拟合值')
# 绘制未来预测值
plt.plot(pred_mean, color='red', label='未来预测值')
# 绘制置信区间
plt.fill_between(conf_int.index,conf_int.iloc[:, 0],conf_int.iloc[:, 1], color='pink', alpha=0.5, label='95%置信区间')
plt.title('ARIMA(2,0,0)模型拟合与预测')
plt.legend()
plt.show()
                               SARIMAX Results                                
==============================================================================
Dep. Variable:                 Births   No. Observations:                  365
Model:                 ARIMA(2, 0, 0)   Log Likelihood               -1234.182
Date:                Sun, 29 Jun 2025   AIC                           2476.364
Time:                        16:08:32   BIC                           2491.963
Sample:                    01-01-1959   HQIC                          2482.563- 12-31-1959                                         
Covariance Type:                  opg                                         
==============================================================================coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         41.9816      0.568     73.885      0.000      40.868      43.095
ar.L1          0.1939      0.055      3.544      0.000       0.087       0.301
ar.L2          0.1139      0.055      2.070      0.038       0.006       0.222
sigma2        50.6301      3.527     14.354      0.000      43.717      57.544
===================================================================================
Ljung-Box (L1) (Q):                   0.02   Jarque-Bera (JB):                18.89
Prob(Q):                              0.89   Prob(JB):                         0.00
Heteroskedasticity (H):               0.96   Skew:                             0.48
Prob(H) (two-sided):                  0.83   Kurtosis:                         3.57
===================================================================================

从视觉上看,这个模型的拟合效果确实很差。橙色的“模型拟合值”线非常平滑,完全没有捕捉到蓝色“原始数据”那些剧烈的峰值和谷值。

那么,为什么一个在统计上“通过检验”的模型,看起来却这么“糟糕”呢?从视觉上看,这个模型的拟合效果确实很差。橙色的“模型拟合值”线非常平滑,完全没有捕捉到蓝色“原始数据”那些剧烈的峰值和谷值。

那么,为什么一个在统计上“通过检验”的模型,看起来却这么“糟糕”呢?

“每日女性出生数量”这个数据集,其内在的随机性(我们称之为“噪音”)非常高。今天比昨天多生了10个孩子,明天又比今天少生了8个,这其中大部分是无法预测的随机事件。

然而,在这个巨大的随机噪音之下,隐藏着一个非常微弱的模式。我们的ARIMA(2,0,0)模型和统计检验发现:今天的出生人数,与昨天(ar.L1)和前天(ar.L2)的出生人数,存在一点点微弱但统计上显著的自相关关系。ARIMA模型就像一个筛子,它的任务是从混杂着沙子(噪音)和金子(模式)的混合物中,把“金子”给筛出来。

  • 橙色线(模型拟合值):这就是模型筛出来的“金子”。它是基于前两天数据计算出的期望值或预测值。因为模式本身是平滑的(只是一个微弱的自相关),所以这条线必然是平滑的。它代表了数据中可预测的部分。
  • 蓝色线与橙色线的差距(残差):这就是被模型筛掉的“沙子”,也就是噪音。这是模型认为不可预测的随机部分。

想象一下,如果我们强行建立一个能完美追踪每一个蓝色数据点的模型。这条橙色线会和蓝色线完全重合。这看起来是不是“拟合得很好”?但这恰恰是“过拟合”(Overfitting)!

这个模型把所有的“噪音”都当成了“模式”来学习。当让它去预测未来时,它会因为学了太多随机噪音而做出非常离谱和不稳定的预测。

一个好的模型,懂“断舍离”——它只学习真正的模式,并勇敢地承认:“剩下的部分,我无法预测,因为它们是随机的。”这就是我们在模型摘要中做的Ljung-Box检验。Prob(Q) = 0.89,这个值远大于0.05。它的意思是:“我们非常有把握地认为,这些残差是纯粹的随机噪音,里面已经没有任何模式可供提取了。”

在时间序列分析中,我们的目标不是创造一个能“复制”历史的“复印机”(过拟合),而是要打造一个能“理解”历史规律的“侦探”(好模型)。这个“侦探”能区分出哪些是线索(模式),哪些是干扰项(噪音)。因此,一个好的模型的残差,必须像白噪音一样“无聊”和“不可预测”。这正是我们在这个例子中看到的。

现在我们来解读下这个输出的表

先看表头,SARIMAX Results

在 statsmodels 库的现代版本中,ARIMA、SARIMA 和 SARIMAX 的后端实现被统一到了一个强大的 SARIMAX 类中。你可以把它理解成一个“全能型”模型引擎。所以结果显示 SARIMAX Results

SARIMAX 是 Seasonal AutoRegressive Integrated Moving Average with eXogenous regressors 的缩写。它是最通用的模型,包含了:

  • ARIMA(p,d,q): 非季节性部分。
  • Seasonal(P,D,Q,m): 季节性部分。
  • eXogenous(X): 外部变量(例如,用天气温度来预测冰淇淋销量)。

简单来说:ARIMA 是 SARIMAX 的一个特例。

然后看第二部分

这是模型的核心参数部分,告诉我们模型具体学到了什么。

  • coef (系数): 这是模型计算出的每个参数的值。

    • const: 常数项/截距。可以理解为序列的基准水平或均值,这里是 41.98,和我们之前图上看到的均值差不多。
    • ar.L1: 滞后1阶的自回归项 (AR) 系数 φ₁。值为 0.1939。
    • ar.L2: 滞后2阶的自回归项 (AR) 系数 φ₂。值为 0.1139。
    • sigma2: 模型残差的方差。值越小说明模型的拟合误差越小。
  • P>|z| (p值): 这是最重要的列! 它检验的是“该系数是否显著不为0”。判断标准: 如果 p值 < 0.05,我们就可以认为这个系数是统计上显著的,它对模型是有贡献的。

    • const 的 p值为 0.000,非常显著。
    • ar.L1 的 p值为 0.000,非常显著。
    • ar.L2 的 p值为 0.038,小于0.05,也是显著的。

在理解上述参数后,此时还有标准差和置信区间这2个参数。

coef 列的值,比如 ar.L1 的 0.1939,是模型通过计算得出的 最有可能的、最佳的估计值。std err(标准误差)衡量的是 系数估计值的不确定性或“抖动幅度”。std err 越小,说明我们的估计越精确、越稳定。如果换一份数据,估计出的系数也不会跑偏太远。这就像一个经验丰富的射手,每次射击都紧紧围绕靶心。std err 是 0.055。这是一个相对较小的值,表明对 0.1939 这个估计是比较有信心的。

[0.087 0.301] 是 ar.L1 系数的 95%置信区间。它的含义是:我们有95%的信心相信,ar.L1 这个参数 真正的、未知的值 落在这个区间之内。我们的最佳估计值 0.1939 只是这个区间中的一个点(通常是中心点)。真实的参数值可能比它大一点,也可能小一点,但很大概率不会超出 [0.087, 0.301] 这个范围。此外,如果置信区间完全不包含0 (像这里的 [0.087, 0.301]),就说明我们有95%的信心断定,这个系数的真实值不是0。这等价于p值小于0.05,即系数是显著的。如果置信区间包含了0 (例如,[-0.1, 0.2]),那就意味着0是一个可能的真实值。我们无法排除“这个系数其实是0,对模型没有作用”的可能性。这等价于p值大于0.05,即系数是不显著的。这2个判断方法是等价的。

结论: 我们选择的 p=2 是合理的,因为两个AR项都是显著的。

第三部分:残差诊断检验

好的残差:应该是模型“吃剩下的、完全没有营养的、随机的白噪声(White Noise)”。如果还剩下隐藏的线索(非白噪声) -> 说明侦探有疏漏,模型还有改进空间。

白噪声的要求:

  1. 无自相关
  2. 方差恒定–如果方差不恒定(比如,越到近期,误差波动越大),说明你的模型在某些时期的预测能力很不可靠。这会影响你对未来预测不确定性的估计。残差随时间变化的图应该像一条宽度稳定的“带子”,而不是一个“喇叭口”或“纺锤”。在检验上对应着:异方差性检验 (Heteroskedasticity test) 的p值应大于0.05。
  3. 均值为0–避免系统性偏差

锦上添花的附加条件:服从正态分布,它主要用于构建准确的预测区间 (Prediction Intervals)。如果残差是正态的,我们就能更有信心地说“未来的值有95%的概率落在某个区间内”。

2.2 国际航空乘客数量实战

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.statespace.sarimax import SARIMAX
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import warningswarnings.filterwarnings("ignore") # 忽略一些模型拟合时产生的警告信息
# 加载数据
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv'
df_air = pd.read_csv(url, header=0, index_col=0, parse_dates=True)
df_air.rename(columns={'#Passengers': 'Passengers'}, inplace=True) # 列名简化# 绘制原始数据
plt.figure(figsize=(12, 6))
plt.plot(df_air['Passengers'])
plt.title('Airline Passengers (1949-1960)')
plt.xlabel('Year')
plt.ylabel('Number of Passengers')
plt.grid(True)
plt.show()

arima无法处理季节性(没有内置季节性差分,只有n阶差分),所以需要先手动处理季节性。

能看到季节性的幅度越来越大,这是一种乘性效应。对数变换是处理这种情况的标准方法,它可以将乘性关系变为加性关系,从而稳定方差。

# 对数变换
df_air['log_passengers'] = np.log(df_air['Passengers'])plt.figure(figsize=(12, 5))
plt.plot(df_air['log_passengers'])
plt.title('Log-Transformed Airline Passengers')
plt.grid(True)
plt.show()

现在,波动的幅度看起来稳定多了,但趋势和季节性依然存在。

# 季节性差分 (m=12)
df_air['log_seasonal_diff'] = df_air['log_passengers'].diff(12)# 丢掉因差分产生的NaN值
deseasonalized_data = df_air['log_seasonal_diff'].dropna()plt.figure(figsize=(12, 5))
plt.plot(deseasonalized_data)
plt.title('Deseasonalized and Log-Transformed Data')
plt.grid(True)
plt.show()

我们成功地去除了季节性模式。现在的数据看起来就像一个有线性趋势的普通时间序列。这种数据正是标准ARIMA模型擅长处理的。

现在,我们为这个 deseasonalized_data 序列选择 (p, d, q) 参数

确定d(差分阶数): 从上图看,数据仍然有明显的上升趋势,所以它不是平稳的。我们需要进行一阶差分来消除这个趋势。因此,d=1。

确定p和q: 我们对差分一次后的序列绘制ACF和PACF图来确定 p 和 q。

# 对去季节性的数据再进行一阶差分,使其平稳
stationary_data = deseasonalized_data.diff(1).dropna()# 绘制ACF和PACF图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
plot_acf(stationary_data, lags=24, ax=ax1)
plot_pacf(stationary_data, lags=24, ax=ax2)
plt.show()

PACF图: 在滞后1阶后迅速截尾(降到置信区间内)。这强烈暗示 p=1。

ACF图: 在滞后1阶后也迅速截尾。这强烈暗示 q=1。

因此,我们为这个预处理后的数据选择的模型是 ARIMA(1, 1, 1)。

ps:这里其实可以看到在12阶的时候超出了置信区间,实际上这个尖峰是残余的季节性信号。即使我们已经做了一次季节性差分 (.diff(12)),数据中仍然保留着一些与12个月前相关的模式。换句话-说,我们手动进行的季节性差分并没有100%完全地消除季节性影响。

我们将使用数据的前11年(到1959年底)作为训练集,最后1年(1960年)作为测试集来验证我们的预测。


from statsmodels.tsa.arima.model import ARIMA# 准备训练数据(经过预处理的)
# 注意:我们是对去季节性的数据进行建模
train_data = deseasonalized_data[:'1959']# 定义并拟合ARIMA(1,1,1)模型
model = ARIMA(train_data, order=(1, 1, 1))
model_fit = model.fit()print(model_fit.summary())# 预测未来12个点(1960年全年)
# 模型预测的是经过变换后的数据
forecast_diff = model_fit.forecast(steps=12)
                               SARIMAX Results                                
==============================================================================
Dep. Variable:      log_seasonal_diff   No. Observations:                  120
Model:                 ARIMA(1, 1, 1)   Log Likelihood                 206.898
Date:                Sun, 29 Jun 2025   AIC                           -407.797
Time:                        16:08:33   BIC                           -399.459
Sample:                    01-01-1950   HQIC                          -404.411- 12-01-1959                                         
Covariance Type:                  opg                                         
==============================================================================coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.L1         -0.5365      0.260     -2.062      0.039      -1.046      -0.027
ma.L1          0.2535      0.300      0.844      0.399      -0.335       0.842
sigma2         0.0018      0.000      9.171      0.000       0.001       0.002
===================================================================================
Ljung-Box (L1) (Q):                   0.04   Jarque-Bera (JB):                 4.07
Prob(Q):                              0.84   Prob(JB):                         0.13
Heteroskedasticity (H):               0.24   Skew:                             0.05
Prob(H) (two-sided):                  0.00   Kurtosis:                         3.90
===================================================================================

可以看到,这里ma(1)不显著,所以q=0 ,我们应该尝试一个更简单的模型:ARIMA(1, 1, 0)。

# 重新拟合一个更简单的模型 ARIMA(1, 1, 0)
model_simplified = ARIMA(train_data, order=(1, 1, 0))
model_fit_simplified = model_simplified.fit()
print(model_fit_simplified.summary())# 比较两个模型的AIC
# 原模型 ARIMA(1,1,1) 的 AIC: -407.797
# 简化模型 ARIMA(1,1,0) 的 AIC 会是多少?
# (运行代码后,ARIMA(1,1,0)的AIC大约是-408.8,比-407.797更小)
                               SARIMAX Results                                
==============================================================================
Dep. Variable:      log_seasonal_diff   No. Observations:                  120
Model:                 ARIMA(1, 1, 0)   Log Likelihood                 206.811
Date:                Sun, 29 Jun 2025   AIC                           -409.622
Time:                        16:08:33   BIC                           -404.064
Sample:                    01-01-1950   HQIC                          -407.365- 12-01-1959                                         
Covariance Type:                  opg                                         
==============================================================================coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
ar.L1         -0.3174      0.068     -4.641      0.000      -0.451      -0.183
sigma2         0.0018      0.000      9.274      0.000       0.001       0.002
===================================================================================
Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):                 4.19
Prob(Q):                              0.99   Prob(JB):                         0.12
Heteroskedasticity (H):               0.25   Skew:                             0.12
Prob(H) (two-sided):                  0.00   Kurtosis:                         3.89
===================================================================================

AIC是一个权衡模型拟合优度和复杂度的指标,AIC值越小,模型通常越好。

可以看到,ARIMA(1,1,0)的AIC大约是-408.8,比 ARIMA(1, 1, 1)的-407.797更小。

现在我们得到了12个预测值 forecast_diff,但这些值是“经过对数变换、季节性差分和一阶差分”后的值。我们需要一步步把它还原回去。这个过程比较繁琐,是手动处理季节性的最大难点。

# 让我们给变量取个更准确的名字
# forecast_deseasonalized 是对“去季节性”序列的直接预测
forecast_deseasonalized = model_fit.forecast(steps=12)# 逆向变换过程
predictions = []# 逐步还原预测值
for i in range(len(forecast_deseasonalized)):# 1. 还原季节性差分 (直接使用预测值)# log(y_t) = y'_t + log(y_{t-12})# y'_t 就是 forecast_deseasonalized[i]# 获取12个月前的历史对数值last_year_log_val = df_air['log_passengers']['1959'].iloc[i]# 加上历史值,得到预测的对数值pred_log = forecast_deseasonalized.iloc[i] + last_year_log_val# 2. 还原对数变换 (exp)pred_original_scale = np.exp(pred_log)predictions.append(pred_original_scale)# 将预测结果转换为Series,方便绘图
# 注意:forecast_deseasonalized 自带了正确的日期索引,可以直接使用
predictions_series = pd.Series(predictions, index=forecast_deseasonalized.index)# --- 重新绘图 ---
plt.figure(figsize=(14, 7))
# 原始数据
plt.plot(df_air['Passengers'], label='Original Data')
# 我们的预测
plt.plot(predictions_series, color='red', linestyle='--', label='ARIMA Forecast (Corrected)')
plt.title('Airline Passengers Forecast using Manual Preprocessing + ARIMA')
plt.xlabel('Year')
plt.ylabel('Number of Passengers')
plt.legend()
plt.grid(True)
plt.show()

时间序列建模的迭代过程:初步选择 -> 拟合检验 -> 模型修正 -> 数据还原。

@浙大疏锦行

http://www.xdnf.cn/news/18973.html

相关文章:

  • Kubernetes 的20 个核心命令分类详解
  • Linex系统网络管理(二)
  • 数据结构第8章 排序(竟成)
  • SqlHelper类库的使用方法
  • .NET周刊【8月第3期 2025-08-17】
  • 鸿蒙ArkUI 基础篇-06-组件基础语法-Column/Row/Text
  • 车载诊断架构 --- 基于整车功能的正向诊断需求开发
  • Dubbo加标签方式
  • Vue3 + 高德地图实现车辆电子围栏监控与报警
  • banner这个文件是怎么请求到后端数据的
  • codeforces(1045)(div2)D. Sliding Tree
  • zookeeper-集群扩缩容
  • 二次校验请求源 IP 是否在 WAF 官方 IP 段内” + “校验是否携带 WAF 专属 HTTP 头
  • 全域管控,一触可达:复合机器人远程监控方案重塑智能制造
  • volitale伪共享问题及解决方案
  • 高效管理远程连接!Remote Desktop Manager 全方位使用指南
  • 对接连连支付(四)-- 收款查询
  • 数据结构:单链表的应用(力扣算法题)第一章
  • 迅睿CMS自定义网站表单:HTML方式调用Select下拉选项数据指南
  • Winsock 操作指南
  • 宝塔面板零基础搭建 WordPress 个人博客与外贸网站 | 新手10分钟上手指南
  • vscode 调试 指定 python文件 运行路径
  • 嵌入式Linux自学不走弯路!670+讲课程!系统学习路线:入门+应用+ARM+驱动+移植+项目 (STM32MP157开发板)
  • Libvio访问异常排查指南
  • 《从有限元到深度学习:我的金属疲劳研究进阶之路》
  • Paimon——官网阅读:主键表
  • 【Kafka】项目整合使用案例
  • 解开 Ansible 任务复用谜题:过滤器用法、Include/Import 本质差异与任务文件价值详解
  • CPU 虚拟化之Cpu Models
  • 微算法科技(NASDAQ:MLGO)突破性FPGA仿真算法技术助力Grover搜索,显著提升量子计算仿真效率