先决条件

本教程假设您对 StatsForecast 有基本了解。如需一个简单示例,请访问快速入门

简介

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

在本教程结束时,您将很好地理解如何将外部回归因子纳入 StatsForecast 的模型中。此外,您将了解如何评估它们的性能,并决定它们是否能帮助提高预测。

大纲

  1. 安装库
  2. 加载并探索数据
  3. 划分训练/测试集
  4. 添加外部回归因子
  5. 创建未来的外部回归因子
  6. 训练模型
  7. 评估结果

提示

您可以使用 Colab 交互式运行此 Notebook

安装库

我们假设您已经安装了 StatsForecast。如果没有,请查看此指南了解如何安装 StatsForecast

# uncomment the following line to install the library
# %pip install statsforecast
import pandas as pd

加载并探索数据

在此示例中,我们将使用来自 M5 竞赛数据集中的一个时间序列。该序列表示 Walmart 商店中某个产品的每日销售额。我们在此 Notebook 中使用的产品-商店组合的 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 方法绘制此产品-商店组合的销售情况。此方法有多个参数,在本 Notebook 中生成图表所需的参数解释如下。

  • df: 一个 pandas 数据帧,包含列 [unique_id, ds, y]。
  • forecasts_df: 一个 pandas 数据帧,包含列 [unique_id, ds] 和模型。
  • 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_iddssell_pricesnap_CA
0FOODS_3_586_CA_32011-01-291.480
1FOODS_3_586_CA_32011-01-301.480
2FOODS_3_586_CA_32011-01-311.480
3FOODS_3_586_CA_32011-02-011.481
4FOODS_3_586_CA_32011-02-021.481

这里的 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 天的销售额。我们将使用相同的预测范围并相应地创建训练集和测试集。

# Extract dates for train and test set 
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_iddsysell_pricesnap_CA
0FOODS_3_586_CA_32011-01-2956.01.480
1FOODS_3_586_CA_32011-01-3055.01.480
2FOODS_3_586_CA_32011-01-3145.01.480
3FOODS_3_586_CA_32011-02-0157.01.481
4FOODS_3_586_CA_32011-02-0254.01.481

创建未来的外部回归因子

我们需要包含外部回归因子的未来值,以便生成预测。请注意,我们已经在 X_test 中获得了这些信息。

X_test.head()
unique_iddssell_pricesnap_CA
1941FOODS_3_586_CA_32016-05-231.680
1942FOODS_3_586_CA_32016-05-241.680
1943FOODS_3_586_CA_32016-05-251.680
1944FOODS_3_586_CA_32016-05-261.680
1945FOODS_3_586_CA_32016-05-271.680

重要提示

如果外部回归因子的未来值不可用,则必须预测这些值,或者从模型中移除这些回归因子。没有它们,就无法生成预测。

训练模型

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

from statsforecast.models import AutoARIMA
# Create a list with the model and its instantiation parameters 
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_iddsAutoARIMAAutoARIMA-lo-95AutoARIMA-hi-95
0FOODS_3_586_CA_32016-05-2372.95627644.109070101.803482
1FOODS_3_586_CA_32016-05-2471.13861140.761467101.515747
2FOODS_3_586_CA_32016-05-2568.14094537.55008398.731804
3FOODS_3_586_CA_32016-05-2665.48558834.84163796.129539
4FOODS_3_586_CA_32016-05-2764.96144134.29197395.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_iddsyAutoARIMAAutoARIMA-lo-95AutoARIMA-hi-95
0FOODS_3_586_CA_32016-05-2366.072.95627644.109070101.803482
1FOODS_3_586_CA_32016-05-2462.071.13861140.761467101.515747
2FOODS_3_586_CA_32016-05-2540.068.14094537.55008398.731804
3FOODS_3_586_CA_32016-05-2672.065.48558834.84163796.129539
4FOODS_3_586_CA_32016-05-2769.064.96144134.29197395.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

# univariate model 
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 作为外部回归因子有助于提高预测。