AutoARIMA 模型
使用 Statsforecast
的 AutoARIMA Model
逐步指南。
目录
- StatsForecast 中的 AutoArima 是什么?
- Arima 模型的定义
- 使用 AutoArima 的优势
- 加载库和数据
- 使用 plot 方法探索数据
- 将数据分割为训练集和测试集
- 使用 StatsForecast 实现 AutoARIMA
- 交叉验证
- 模型评估
- 参考资料
StatsForecast 中的 AutoArima 是什么?
AutoARIMA 是一种时间序列模型,它使用自动化过程为给定的时间序列选择最佳 ARIMA(自回归积分滑动平均)模型参数。ARIMA 是一种广泛用于时间序列建模和预测的统计模型。
AutoARIMA 模型中的自动参数选择过程采用统计和优化技术(例如 Akaike 信息准则 (AIC) 和交叉验证),以确定 ARIMA 模型的自回归、积分和滑动平均参数的最佳值。
自动参数选择很有用,因为如果没有对生成时间序列的基础随机过程的深入理解,很难确定给定时间序列的 ARIMA 模型最佳参数。autoARIMA 模型自动化了参数选择过程,可以为时间序列建模和预测提供快速有效的解决方案。
statsforecast.models
库提供了 Python 的 AutoARIMA
函数实现,可以自动为给定时间序列选择 ARIMA 模型的最佳参数。
Arima 模型的定义
ARIMA 模型(自回归积分滑动平均)过程是自回归过程 AR(p)、积分 I(d) 和滑动平均过程 MA(q) 的组合。
与 ARMA 过程一样,ARIMA 过程指出,当前值取决于过去的值(来自 AR(p) 部分)和过去的误差(来自 MA(q) 部分)。然而,ARIMA 过程不使用表示为 yt 的原序列,而是使用表示为 的差分序列。请注意, 可以表示经过多次差分的序列。
因此,ARIMA(p,d,q) 过程的数学表达式指出,差分序列 的当前值等于一个常数 、差分序列的过去值 、差分序列的均值 、过去的误差项 以及当前的误差项 ,如方程所示
其中 是差分序列(可能经过多次差分)。等号右侧的“预测变量”包括 的滞后值和滞后误差。我们称之为 ARIMA(p,d,q) 模型,其中
p | 自回归部分的阶数 |
d | 涉及的差分次数 |
q | 滑动平均部分的阶数 |
用于自回归和滑动平均模型的平稳性和可逆性条件同样适用于 ARIMA 模型。
我们已经讨论过的许多模型都是 ARIMA 模型的特例,如表所示
模型 | p d q | 差分序列 | 模型类型 |
---|---|---|---|
Arima(0,0,0) | 0 0 0 | 白噪声 | |
ARIMA (0,1,0) | 0 1 0 | 随机游走 | |
ARIMA (0,2,0) | 0 2 0 | 常数 | |
ARIMA (1,0,0) | 1 0 0 | AR(1): 一阶自回归模型 | |
ARIMA (2, 0, 0) | 2 0 0 | AR(2): 二阶自回归模型 | |
ARIMA (1, 1, 0) | 1 1 0 | 差分一阶自回归模型 | |
ARIMA (0, 1, 1) | 0 1 1 | 简单指数平滑 | |
ARIMA (0, 0, 1) | 0 0 1 | MA(1):一阶回归模型 | |
ARIMA (0, 0, 2) | 0 0 2 | MA(2):二阶回归模型 | |
ARIMA (1, 0, 1) | 1 0 1 | ARMA 模型 | |
ARIMA (1, 1, 1) | 1 1 1 | ARIMA 模型 | |
ARIMA (1, 1, 2) | 1 1 2 | 阻尼趋势线性指数平滑 | |
ARIMA (0, 2, 1) 或 (0,2,2) | 0 2 1 | 线性指数平滑 |
一旦我们开始以这种方式组合组件以形成更复杂的模型,使用滞后算子(backshift notation)会容易得多。例如,公式 (1) 可以用滞后算子表示为
选择合适的 p、d 和 q 值可能很困难。然而,statsforecast
库中的 AutoARIMA()
函数将自动为您完成此操作。
更多信息请参阅此处
加载库和数据
使用 AutoARIMA()
模型进行时间序列建模和预测有几个优点,包括
-
参数选择过程自动化:
AutoARIMA()
函数自动化了 ARIMA 模型参数选择过程,通过消除手动尝试不同参数组合的需要,为用户节省时间和精力。 -
降低预测误差:通过自动选择最优参数,与手动选择的 ARIMA 模型相比,ARIMA 模型可以提高预测的准确性。
-
识别复杂模式:
AutoARIMA()
函数可以识别数据中可能难以通过可视化或其他时间序列建模技术检测到的复杂模式。 -
参数选择方法的灵活性:ARIMA 模型可以使用不同的方法来选择最优参数,例如赤池信息准则(AIC)、交叉验证等,这使用户能够选择最适合其需求的方法。
通常,使用 AutoARIMA()
函数有助于提高时间序列建模和预测的效率和准确性,特别是对于不熟悉手动选择 ARIMA 模型参数的用户。
主要结果
我们比较了与 pmdarima、Rob Hyndman 的 forecast 包以及 Facebook 的 Prophet 在准确性和速度上的差异。我们使用了 M4 竞赛中的 Daily
(日度)、Hourly
(小时)和 Weekly
(周度)数据。
下表总结了结果。可以看出,我们的 auto_arima
在准确性(由 MASE
损失衡量)和时间方面是最好的模型,甚至优于 R 中的原始实现。
数据集 | 指标 | auto_arima_nixtla | auto_arima_pmdarima [1] | auto_arima_r | prophet |
---|---|---|---|---|---|
日度 | MASE | 3.26 | 3.35 | 4.46 | 14.26 |
日度 | 时间 | 1.41 | 27.61 | 1.81 | 514.33 |
小时 | MASE | 0.92 | — | 1.02 | 1.78 |
小时 | 时间 | 12.92 | — | 23.95 | 17.27 |
周度 | MASE | 2.34 | 2.47 | 2.58 | 7.29 |
周度 | 时间 | 0.42 | 2.92 | 0.22 | 19.82 |
[1] pmdarima
的 auto_arima
模型在小时数据上存在问题。已开启一个 issue。
下表总结了数据详情。
组 | 系列数 | 平均长度 | 标准差长度 | 最小长度 | 最大长度 |
---|---|---|---|---|---|
日度 | 4,227 | 2,371 | 1,756 | 107 | 9,933 |
小时 | 414 | 901 | 127 | 748 | 1,008 |
周度 | 359 | 1,035 | 707 | 93 | 2,610 |
加载库和数据
提示
需要安装 Statsforecast。安装方法请参阅说明。
接下来,我们导入绘图库并配置绘图样式。
加载数据
observation_date | IPG3113N | |
---|---|---|
0 | 1972-01-01 | 85.6945 |
1 | 1972-02-01 | 71.8200 |
2 | 1972-03-01 | 66.0229 |
3 | 1972-04-01 | 64.5645 |
4 | 1972-05-01 | 65.0100 |
StatsForecast 的输入始终是一个长格式的数据帧,包含三列:unique_id、ds 和 y
-
unique_id
(字符串、整数或类别)代表时间序列的标识符。 -
ds
(日期戳)列应采用 Pandas 期望的格式,日期通常为 YYYY-MM-DD,时间戳通常为 YYYY-MM-DD HH:MM:SS。 -
y
(数值)代表我们希望预测的度量值。
ds | y | unique_id | |
---|---|---|---|
0 | 1972-01-01 | 85.6945 | 1 |
1 | 1972-02-01 | 71.8200 | 1 |
2 | 1972-03-01 | 66.0229 | 1 |
3 | 1972-04-01 | 64.5645 | 1 |
4 | 1972-05-01 | 65.0100 | 1 |
我们需要将 ds
从 object
类型转换为 datetime 类型。
使用 plot 方法探索数据
使用 StatsForecast 类中的 plot 方法绘制一个时间序列。此方法会从数据集中打印一个随机系列,对进行基本探索性数据分析 (EDA) 非常有用。
自相关图
时间序列分解
如何以及为何分解时间序列?
在时间序列分析中,为了预测新值,了解过去的数据非常重要。更正式地说,了解数值随时间变化的模式非常重要。许多原因可能导致我们的预测值偏离正确的方向。基本上,时间序列由四个组成部分组成。这些组成部分的变化导致时间序列模式的改变。这些组成部分是:
- 水平项: 这是随时间平均的主要值。
- 趋势项: 趋势是导致时间序列呈现上升或下降模式的值。
- 季节项: 这是时间序列中周期性发生的事件,持续时间较短,导致时间序列呈现短期上升或下降模式。
- 残差/噪声项: 这些是时间序列中的随机变化。
随着时间的推移,这些组成部分的组合形成了时间序列。大多数时间序列由水平项和噪声/残差项组成,而趋势项或季节项是可选的。
如果季节项和趋势项是时间序列的一部分,那么会对预测值产生影响。因为预测时间序列的模式可能与之前的时间序列不同。
时间序列中组成部分的组合可以是两种类型: * 加法模型 * 乘法模型
加法时间序列模型
如果时间序列的组成部分相加形成时间序列。则称该时间序列为加法时间序列。通过可视化,我们可以说如果时间序列的上升或下降模式在整个序列中相似,则它是加法模型。任何加法时间序列的数学函数可以表示为:
乘法时间序列模型
如果时间序列的组成部分相乘形成时间序列,则称该时间序列为乘法时间序列。从可视化角度看,如果时间序列随时间呈现指数增长或下降,则可以将其视为乘法时间序列。乘法时间序列的数学函数可以表示为。
将数据分割为训练集和测试集
我们将数据分为两部分:1. 用于训练 AutoArima
模型的数据 2. 用于测试模型的数据
对于测试数据,我们将使用最后 12 个月的数据来测试和评估模型的性能。
现在让我们绘制训练数据和测试数据。
使用 StatsForecast 实现 AutoArima
加载库
实例化模型
导入并实例化模型。设置 season_length
参数有时很棘手。大师 Rob Hyndmann 关于季节周期的文章可能很有帮助。
我们通过实例化一个新的 StatsForecast 对象并使用以下参数来拟合模型
models:模型列表。从模型中选择您想要的模型并导入它们。
-
freq:
一个字符串,表示数据的频率。(请参阅 panda 可用的频率。) -
n_jobs:
n_jobs:整数,并行处理中使用的作业数,使用 -1 表示所有核心。 -
fallback_model:
如果某个模型失败,则使用的备用模型。
任何设置都通过构造函数传递。然后调用其 fit 方法并传入历史数据帧。
拟合模型
输入模型后,我们可以使用arima_string
函数查看模型找到的参数。
自动化过程告诉我们找到的最佳模型形式为 ARIMA(4,0,3)(0,1,1)[12]
,这意味着我们的模型包含 ,即它包含一个非季节性自回归成分;另一方面,我们的模型包含一个季节性部分,其阶数为 ,即它包含一个季节性差分;以及 ,它包含 3 个移动平均成分。
为了了解模型项的值,我们可以使用以下语句来查看模型的全部结果。
现在让我们可视化模型的残差。
如我们所见,上面得到的结果是一个字典输出,要从字典中提取每个元素,我们将使用 .get()
函数提取元素,然后将其保存在 pd.DataFrame()
中。
残差模型 | |
---|---|
0 | 0.085694 |
1 | 0.071820 |
2 | 0.066022 |
… | … |
533 | 1.615486 |
534 | -0.394285 |
535 | -6.733548 |
要生成预测,我们只需使用 predict 方法并指定预测范围 (h)。此外,为了计算与预测相关的预测区间,我们可以包含 level 参数,该参数接收一个列表,其中包含我们想要构建的预测区间的置信水平。在本例中,我们将只计算 90% 的预测区间 (level=[90])。
预测方法
如果您想在具有多个时间序列或模型的生产环境中提高速度,我们建议使用 StatsForecast.forecast
方法,而不是 .fit
和 .predict
。
主要区别在于 .forecast
不存储拟合值,并且在分布式环境中具有高度可扩展性。
forecast 方法接受两个参数:预测未来 h
(范围)和 level
。
-
h(整数):
表示未来 h 步的预测。在本例中,即未来 12 个月。 -
level(浮点数列表):
此可选参数用于概率预测。设置预测区间的置信水平(或置信百分位数)。例如,level=[90]
表示模型期望真实值有 90% 的时间落在此区间内。
这里的 forecast 对象是一个新的数据帧,包含模型名称和 y 帽值(预测值)的列,以及不确定性区间的列。根据您的计算机性能,此步骤大约需要 1 分钟。(如果您想将速度提高到几秒钟,请移除 AutoModels,例如 ARIMA
和 Theta
)
unique_id | ds | AutoARIMA | |
---|---|---|---|
0 | 1 | 2016-09-01 | 111.235874 |
1 | 1 | 2016-10-01 | 124.948376 |
2 | 1 | 2016-11-01 | 125.401639 |
3 | 1 | 2016-12-01 | 123.854826 |
4 | 1 | 2017-01-01 | 110.439451 |
unique_id | ds | y | AutoARIMA | |
---|---|---|---|---|
0 | 1 | 1972-01-01 | 85.6945 | 85.608806 |
1 | 1 | 1972-02-01 | 71.8200 | 71.748180 |
2 | 1 | 1972-03-01 | 66.0229 | 65.956878 |
… | … | … | … | … |
533 | 1 | 2016-06-01 | 102.4044 | 100.788914 |
534 | 1 | 2016-07-01 | 102.9512 | 103.345485 |
535 | 1 | 2016-08-01 | 104.6977 | 111.431248 |
使用 forecast 方法添加 95% 置信区间
unique_id | ds | AutoARIMA | AutoARIMA-lo-95 | AutoARIMA-hi-95 | |
---|---|---|---|---|---|
0 | 1 | 2016-09-01 | 111.235874 | 104.140621 | 118.331128 |
1 | 1 | 2016-10-01 | 124.948376 | 116.244661 | 133.652090 |
2 | 1 | 2016-11-01 | 125.401639 | 115.882093 | 134.921185 |
… | … | … | … | … | … |
9 | 1 | 2017-06-01 | 98.304446 | 85.884572 | 110.724320 |
10 | 1 | 2017-07-01 | 99.630306 | 87.032356 | 112.228256 |
11 | 1 | 2017-08-01 | 105.426708 | 92.639159 | 118.214258 |
带有置信区间的 Predict 方法
要生成预测,请使用 predict 方法。
predict 方法接受两个参数:预测未来 h
(范围)和 level
。
-
h(整数):
表示未来 h 步的预测。在本例中,即未来 12 个月。 -
level(浮点数列表):
此可选参数用于概率预测。设置预测区间的置信水平(或置信百分位数)。例如,level=[95]
表示模型期望真实值有 95% 的时间落在此区间内。
这里的 forecast 对象是一个新的数据帧,包含模型名称和 y 帽值(预测值)的列,以及不确定性区间的列。
此步骤应少于 1 秒。
unique_id | ds | AutoARIMA | |
---|---|---|---|
0 | 1 | 2016-09-01 | 111.235874 |
1 | 1 | 2016-10-01 | 124.948376 |
2 | 1 | 2016-11-01 | 125.401639 |
… | … | … | … |
9 | 1 | 2017-06-01 | 98.304446 |
10 | 1 | 2017-07-01 | 99.630306 |
11 | 1 | 2017-08-01 | 105.426708 |
unique_id | ds | AutoARIMA | AutoARIMA-lo-95 | AutoARIMA-lo-80 | AutoARIMA-hi-80 | AutoARIMA-hi-95 | |
---|---|---|---|---|---|---|---|
0 | 1 | 2016-09-01 | 111.235874 | 104.140621 | 106.596537 | 115.875211 | 118.331128 |
1 | 1 | 2016-10-01 | 124.948376 | 116.244661 | 119.257323 | 130.639429 | 133.652090 |
2 | 1 | 2016-11-01 | 125.401639 | 115.882093 | 119.177142 | 131.626136 | 134.921185 |
… | … | … | … | … | … | … | … |
9 | 1 | 2017-06-01 | 98.304446 | 85.884572 | 90.183527 | 106.425365 | 110.724320 |
10 | 1 | 2017-07-01 | 99.630306 | 87.032356 | 91.392949 | 107.867663 | 112.228256 |
11 | 1 | 2017-08-01 | 105.426708 | 92.639159 | 97.065379 | 113.788038 | 118.214258 |
我们可以使用 pandas 函数 pd.concat()
将预测结果与历史数据连接起来,然后将此结果用于绘图。
y | unique_id | AutoARIMA | AutoARIMA-lo-95 | AutoARIMA-lo-80 | AutoARIMA-hi-80 | AutoARIMA-hi-95 | |
---|---|---|---|---|---|---|---|
ds | |||||||
2000-05-01 | 108.7202 | 1 | NaN | NaN | NaN | NaN | NaN |
2000-06-01 | 114.2071 | 1 | NaN | NaN | NaN | NaN | NaN |
2000-07-01 | 111.8737 | 1 | NaN | NaN | NaN | NaN | NaN |
… | … | … | … | … | … | … | … |
2017-06-01 | NaN | 1 | 98.304446 | 85.884572 | 90.183527 | 106.425365 | 110.724320 |
2017-07-01 | NaN | 1 | 99.630306 | 87.032356 | 91.392949 | 107.867663 | 112.228256 |
2017-08-01 | NaN | 1 | 105.426708 | 92.639159 | 97.065379 | 113.788038 | 118.214258 |
现在让我们可视化预测结果以及时间序列的历史数据,同时绘制我们在进行 95% 置信度预测时获得的置信区间。
交叉验证
在之前的步骤中,我们使用了历史数据来预测未来。然而,为了评估其准确性,我们还想了解模型在过去会如何表现。要评估您的模型在数据上的准确性和稳健性,请执行交叉验证。
对于时间序列数据,交叉验证是通过在历史数据上定义一个滑动窗口并预测其后的一段时间来完成的。这种形式的交叉验证使我们能够更准确地估计模型在更广泛的时间点上的预测能力,同时保持训练集中的数据连续性,这是模型所要求的。
下图描述了这种交叉验证策略
执行时间序列交叉验证
时间序列模型的交叉验证被认为是最佳实践,但大多数实现都非常慢。Statsforecast 库将交叉验证实现为分布式操作,从而减少执行过程所需的时间。如果数据集很大,您还可以使用 Ray、Dask 或 Spark 在分布式集群中执行交叉验证。
在本例中,我们希望评估每个模型在过去 5 个月中的性能 (n_windows=5)
,每隔 12 个月预测一次 (step_size=12)
。根据您的计算机性能,此步骤大约需要 1 分钟。
StatsForecast 类中的 cross_validation 方法接受以下参数。
-
df:
训练数据帧 -
h(整数):
表示预测未来的 h 步。在本例中,即未来 12 个月。 -
step_size(整数):
每个窗口之间的步长。换句话说:您希望多久运行一次预测过程。 -
n_windows(整数):
用于交叉验证的窗口数量。换句话说:您希望评估过去多少个预测过程。
crossvaldation_df 对象是一个新的数据帧,包含以下列
unique_id:
时间序列标识符ds:
日期戳或时间索引cutoff:
n_windows 的最后一个日期戳或时间索引。y:
真实值"model":
包含模型名称和拟合值的列。
unique_id | ds | cutoff | y | AutoARIMA | |
---|---|---|---|---|---|
0 | 1 | 2011-09-01 | 2011-08-01 | 93.9062 | 105.235606 |
1 | 1 | 2011-10-01 | 2011-08-01 | 116.7634 | 118.739813 |
2 | 1 | 2011-11-01 | 2011-08-01 | 116.8258 | 114.572924 |
3 | 1 | 2011-12-01 | 2011-08-01 | 114.9563 | 114.991219 |
4 | 1 | 2012-01-01 | 2011-08-01 | 99.9662 | 100.133142 |
模型评估
现在我们将使用预测结果来评估我们的模型,我们将使用不同类型的指标,如 MAE、MAPE、MASE、RMSE、SMAPE 来评估准确性。
unique_id | 指标 | AutoARIMA | |
---|---|---|---|
0 | 1 | mae | 5.012894 |
1 | 1 | mape | 0.045046 |
2 | 1 | mase | 0.967601 |
3 | 1 | rmse | 5.680362 |
4 | 1 | smape | 0.022673 |