外生回归变量

在本笔记本中,我们将把外生回归变量纳入StatsForecast模型中。

本教程假设您对StatsForecast有基本的了解。有关最小示例,请访问快速入门

引言

外生回归变量是指可能影响时间序列值的变量。它们可能与正在预测的变量没有直接关系,但仍然可以对其产生影响。外生回归变量的例子包括天气数据、经济指标或促销销售。它们通常来自外部来源,通过将这些变量纳入预测模型,可以提高我们预测的准确性。

在本教程结束时,您将对如何将外生回归变量纳入StatsForecast的模型有一个良好的理解。此外,您还将看到如何评估它们的性能,并决定它们是否能够帮助改善预测。

大纲

  1. 安装库
  2. 加载和探索数据
  3. 拆分训练/测试集
  4. 添加外生回归变量
  5. 创建未来外生回归变量
  6. 训练模型
  7. 评估结果
Tip

您可以使用 Colab 交互式运行此笔记本 在 Colab 中打开

安装库

我们假设您已经安装了StatsForecast。如果没有,请查看本指南以获取如何安装StatsForecast的说明。

# 取消注释以下行以安装库
# %pip 安装 statsforecast
import os

import pandas as pd
# 这样,预测方法的输出结果中就会包含一个id列。 
# 而不是作为索引
os.environ['NIXTLA_ID_AS_COL'] = '1'

加载和探索数据

在本例中,我们将使用来自 M5 Competition 数据集的单个时间序列。该序列代表了一家沃尔玛商店中某产品的每日销售情况。我们将在本笔记中使用的产品-商店组合的 unique_id = FOODS_3_586_CA_3。选择这个时间序列是因为它不是间歇性的,并且具有对预测有用的外生回归变量。

我们将加载以下数据帧:

  • Y_ts: (pandas DataFrame) 目标时间序列,包含列 [unique_id, ds, y]。
  • X_ts: (pandas DataFrame) 外生时间序列,包含列 [unique_id, ds, 外生回归变量]。
base_url = 'https://datasets-nixtla.s3.amazonaws.com'
filters = [('unique_id', '=', 'FOODS_3_586_CA_3')]
Y_ts = pd.read_parquet(f'{base_url}/m5_y.parquet', filters=filters)
X_ts = pd.read_parquet(f'{base_url}/m5_x.parquet', filters=filters)

我们可以使用来自StatsForecast类的statsforecast.plot方法来绘制这个产品-商店组合的销售情况。此方法有多个参数,在本笔记本中生成图表所需的参数在下面进行了说明。

  • df:一个包含[unique_iddsy]列的pandas数据框。
  • forecasts_df:一个包含[unique_idds]及模型的pandas数据框。
  • engine:str = matplotlib。也可以是plotlyplotly生成交互式图表,而matplotlib生成静态图表。
from statsforecast import StatsForecast 
StatsForecast.plot(Y_ts)

M5竞赛包括几个外生回归变量。在这里,我们将使用以下两个。

  • sell_price: 给定商店的产品价格。价格按周提供。
  • snap_CA: 一个二元变量,指示商店是否允许SNAP购买(如果允许则为1,否则为0)。SNAP代表补充营养援助计划,它为个人和家庭提供资金,以帮助他们购买食品产品。
X_ts = X_ts[['unique_id', 'ds', 'sell_price', 'snap_CA']]
X_ts.head()
unique_id ds sell_price snap_CA
0 FOODS_3_586_CA_3 2011-01-29 1.48 0
1 FOODS_3_586_CA_3 2011-01-30 1.48 0
2 FOODS_3_586_CA_3 2011-01-31 1.48 0
3 FOODS_3_586_CA_3 2011-02-01 1.48 1
4 FOODS_3_586_CA_3 2011-02-02 1.48 1

在这里,unique_id 是一个类别,但对于外生回归变量,它需要是一个字符串。

X_ts['unique_id'] = X_ts.unique_id.astype(str)

我们可以使用plotly绘制外生回归变量。我们可以使用statsforecast.plot,但那时必须将一个回归变量重命名为y,并且在生成预测之前必须将名称改回原始名称。

StatsForecast.plot(Y_ts, X_ts, max_insample_length=0)

从这个图中,我们可以得出结论:价格已增加两倍,并且SNAP在规则的间隔发生。

切分训练/测试集

在M5竞赛中,参与者需要预测数据集中最后28天的销售额。我们将使用相同的预测范围,并相应地创建训练集和测试集。

# 提取训练集和测试集的日期 
dates = Y_ts['ds'].unique()
dtrain = dates[:-28]
dtest = dates[-28:]

Y_train = Y_ts.query('ds in @dtrain')
Y_test = Y_ts.query('ds in @dtest') 

X_train = X_ts.query('ds in @dtrain') 
X_test = X_ts.query('ds in @dtest')

添加外部回归变量

外生回归变量需要放在目标变量 y 之后。

train = Y_train.merge(X_ts, how = 'left', on = ['unique_id', 'ds']) 
train.head()
unique_id ds y sell_price snap_CA
0 FOODS_3_586_CA_3 2011-01-29 56.0 1.48 0
1 FOODS_3_586_CA_3 2011-01-30 55.0 1.48 0
2 FOODS_3_586_CA_3 2011-01-31 45.0 1.48 0
3 FOODS_3_586_CA_3 2011-02-01 57.0 1.48 1
4 FOODS_3_586_CA_3 2011-02-02 54.0 1.48 1

创建未来的外生回归变量

我们需要包含外生回归变量的未来值,以便能够生成预测。请注意,我们已经在X_test中拥有这些信息。

X_test.head()
unique_id ds sell_price snap_CA
1941 FOODS_3_586_CA_3 2016-05-23 1.68 0
1942 FOODS_3_586_CA_3 2016-05-24 1.68 0
1943 FOODS_3_586_CA_3 2016-05-25 1.68 0
1944 FOODS_3_586_CA_3 2016-05-26 1.68 0
1945 FOODS_3_586_CA_3 2016-05-27 1.68 0
Important

如果外生回归变量的未来值不可用,则必须进行预测,或者需要从模型中消除这些回归变量。没有它们,就无法生成预测。

训练模型

为了生成预测,我们将使用 AutoARIMA,这是 StatsForecast 中可用的模型之一,允许外生回归变量。要使用此模型,我们首先需要从 statsforecast.models 导入它,然后我们需要实例化它。考虑到我们正在处理日数据,我们需要设置 season_length = 7

from statsforecast.models import AutoARIMA
# 创建一个包含模型及其实例化参数的列表 
models = [AutoARIMA(season_length=7)]

接下来,我们需要实例化一个新的 StatsForecast 对象,其具有以下参数:

  • df:包含训练数据的数据框。
  • models:在前一步中定义的模型列表。
  • freq:一个字符串,指示数据的频率。请参见 pandas 可用的频率
  • n_jobs:一个整数,指示用于并行处理的作业数量。使用 -1 来选择所有核心。
sf = StatsForecast(
    models=models, 
    freq='D', 
    n_jobs=1,
)

现在我们准备生成预测。为此,我们将使用 forecast 方法,接受以下参数。

  • h:一个整数,代表预测的时间范围。在这种情况下,我们将预测接下来的28天。
  • X_df:一个 pandas 数据框,包含外生回归变量的未来值。
  • level:一个包含预测区间置信水平的浮点数列表。例如,level=[95] 表示该值范围应以95%的概率包含实际未来值。
horizon = 28
level = [95]

fcst = sf.forecast(df=train, h=horizon, X_df=X_test, level=level)
fcst.head()
unique_id ds AutoARIMA AutoARIMA-lo-95 AutoARIMA-hi-95
0 FOODS_3_586_CA_3 2016-05-23 72.956276 44.109070 101.803482
1 FOODS_3_586_CA_3 2016-05-24 71.138611 40.761467 101.515747
2 FOODS_3_586_CA_3 2016-05-25 68.140945 37.550083 98.731804
3 FOODS_3_586_CA_3 2016-05-26 65.485588 34.841637 96.129539
4 FOODS_3_586_CA_3 2016-05-27 64.961441 34.291973 95.630905

我们可以使用上述描述的 statsforecast.plot 方法绘制预测结果。

StatsForecast.plot(Y_ts, fcst, max_insample_length=28*2)

评估结果

我们将合并测试集和预测结果,以使用平均绝对误差 (MAE) 评估准确性。

res = Y_test.merge(fcst, how='left', on=['unique_id', 'ds'])
res.head()
unique_id ds y AutoARIMA AutoARIMA-lo-95 AutoARIMA-hi-95
0 FOODS_3_586_CA_3 2016-05-23 66.0 72.956276 44.109070 101.803482
1 FOODS_3_586_CA_3 2016-05-24 62.0 71.138611 40.761467 101.515747
2 FOODS_3_586_CA_3 2016-05-25 40.0 68.140945 37.550083 98.731804
3 FOODS_3_586_CA_3 2016-05-26 72.0 65.485588 34.841637 96.129539
4 FOODS_3_586_CA_3 2016-05-27 69.0 64.961441 34.291973 95.630905
mae = abs(res['y']-res['AutoARIMA']).mean()
print('The MAE with exogenous regressors is '+str(round(mae,2)))
The MAE with exogenous regressors is 11.42

为了检查外生回归变量是否有用,我们需要重新生成预测,这次不使用这些变量。为此,我们只需将不包含外生变量的数据框传递给 forecast 方法。请注意,数据仅包括 unique_iddsyforecast 方法不再需要外生回归变量 X_df 的未来值。

# 单变量模型 
fcst_u = sf.forecast(df=train[['unique_id', 'ds', 'y']], h=28)

res_u = Y_test.merge(fcst_u, how='left', on=['unique_id', 'ds'])
mae_u = abs(res_u['y']-res_u['AutoARIMA']).mean()
print('The MAE without exogenous regressors is '+str(round(mae_u,2)))
The MAE without exogenous regressors is 12.18

因此,我们可以得出结论,使用 sell_pricesnap_CA 作为外部回归变量有助于提高预测精度。

Give us a ⭐ on Github