外生变量

外生变量可以提供额外的信息,从而大大提高预测的准确性。一些例子包括用于需求预测的价格或未来促销变量,以及用于电力负荷预测的天气数据。在本笔记中,我们展示了如何向NeuralForecast模型添加不同类型的外生变量,以便对法国和比利时市场进行次日每小时电力价格预测(EPF)。

所有NeuralForecast模型都能够结合外生变量来建模以下条件预测分布: \[\mathbb{P}(\mathbf{y}_{t+1:t+H} \;|\; \mathbf{y}_{[:t]},\; \mathbf{x}^{(h)}_{[:t]},\; \mathbf{x}^{(f)}_{[:t+H]},\; \mathbf{x}^{(s)} )\]

其中回归变量包括静态外生变量\(\mathbf{x}^{(s)}\),历史外生变量\(\mathbf{x}^{(h)}_{[:t]}\),预测时可用的外生变量\(\mathbf{x}^{(f)}_{[:t+H]}\)和自回归特征\(\mathbf{y}_{[:t]}\)。根据训练损失,模型输出可以是点预测(位置估计)或不确定区间(分位数)。

我们将向您展示如何在数据中包含外生变量,如何将变量指定给模型,以及如何使用未来的外生变量生成预测。

Important

本指南假设您对NeuralForecast库有基本了解。有关最简例子请访问快速入门指南。

您可以使用 Google Colab 的 GPU 运行这些实验。

在 Colab 中打开

1. 库

%%capture
!pip install neuralforecast

2. 加载数据

df 数据框包含了训练模型所需的目标和外生变量的历史信息。unique_id 列用于识别市场,ds 列包含日期戳,y 列为电价。

同时包含历史和未来的时间变量作为列。在这个示例中,我们将系统负荷(system_load)作为历史数据添加。对于未来变量,我们包括了电力生产的预测(gen_forecast)和星期几(week_day)。电力系统的需求和供给对价格有显著影响,将这些变量包含入模型大大提升了模型的性能,正如 Olivares 等(2022)所示。

历史变量和未来变量的区分将作为模型的参数在后面作出。

import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('https://datasets-nixtla.s3.amazonaws.com/EPF_FR_BE.csv')
df['ds'] = pd.to_datetime(df['ds'])
df.head()
unique_id ds y gen_forecast system_load week_day
0 FR 2015-01-01 00:00:00 53.48 76905.0 74812.0 3
1 FR 2015-01-01 01:00:00 51.93 75492.0 71469.0 3
2 FR 2015-01-01 02:00:00 48.76 74394.0 69642.0 3
3 FR 2015-01-01 03:00:00 42.27 72639.0 66704.0 3
4 FR 2015-01-01 04:00:00 38.41 69347.0 65051.0 3
Tip

日历变量,例如星期几、月份和年份,对于捕捉长期季节性非常有用。

plt.figure(figsize=(15,5))
plt.plot(df[df['unique_id']=='FR']['ds'], df[df['unique_id']=='FR']['y'])
plt.xlabel('Date')
plt.ylabel('Price [EUR/MWh]')
plt.grid()

将静态变量添加到一个单独的 static_df 数据框中。在这个示例中,我们使用电力市场的一热编码。static_df 必须包含 df 数据框中每个 unique_id 的一个观测值(行),不同的静态变量作为列。

static_df = pd.read_csv('https://datasets-nixtla.s3.amazonaws.com/EPF_FR_BE_static.csv')
static_df.head()
unique_id market_0 market_1
0 FR 1 0
1 BR 0 1

3. 使用外生变量进行训练

我们通过外生变量是否反映建模数据的静态或时间依赖特征来进行区分。

  • 静态外生变量: 静态外生变量为每个时间序列提供时间不变的信息。当模型使用全局参数来预测多个时间序列时,这些变量允许在具有相似静态变量水平的时间序列组之间共享信息。静态变量的示例包括区域标识符、产品组等标识符。

  • 历史外生变量: 这种时间依赖的外生变量仅限于过去观察值。它的预测能力依赖于格兰杰因果关系,因为其过去的值可以为目标变量 \(\mathbf{y}\) 的未来值提供重要信息。

  • 未来外生变量: 与历史外生变量相反,预测时可获得未来值。示例包括日历变量、天气预报和已知事件,这些事件可能导致大幅波动,如计划中的促销活动。

要向模型添加外生变量,首先在初始化时将来自之前数据框的每个变量的名称指定给相应的模型超参数:futr_exog_listhist_exog_liststat_exog_list。我们还将 horizon 设置为 24,以生成下一天的每小时预测,并将 input_size 设置为使用最近 5 天的数据作为输入。

from neuralforecast.auto import NHITS, BiTCN
from neuralforecast.core import NeuralForecast

import logging
logging.getLogger("pytorch_lightning").setLevel(logging.WARNING)
c:\Users\ospra\miniconda3\envs\neuralforecast\lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
2024-07-15 11:16:36,090 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.
2024-07-15 11:16:36,499 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.
horizon = 24 # 日前日度预测
models = [NHITS(h = horizon,
                input_size = 5*horizon,
                futr_exog_list = ['gen_forecast', 'week_day'], # <- 未来外生变量
                hist_exog_list = ['system_load'], # <- 历史外生变量
                stat_exog_list = ['market_0', 'market_1'], # <- 静态外生变量
                scaler_type = 'robust'),
          BiTCN(h = horizon,
                input_size = 5*horizon,
                futr_exog_list = ['gen_forecast', 'week_day'], # <- 未来外生变量
                hist_exog_list = ['system_load'], # <- 历史外生变量
                stat_exog_list = ['market_0', 'market_1'], # <- 静态外生变量
                scaler_type = 'robust',
                ),                
                ]
Seed set to 1
Seed set to 1
Tip

在包含外生变量时,请始终通过设置 scaler_type 超参数来使用缩放器。缩放器将对所有时间特征进行缩放:目标变量 y、历史变量和未来变量。

Important

确保未来变量和历史变量正确放置。将历史变量定义为未来变量将导致数据泄漏。

接下来,将数据集传递给 fit 方法的 dfstatic_df 输入。

%%capture
nf = NeuralForecast(models=models, freq='H')
nf.fit(df=df,
       static_df=static_df)

4. 使用外生变量的预测

在预测价格之前,我们需要收集我们想要预测的那一天的未来外生变量。定义一个新的数据框 (futr_df),其中包含 unique_idds 和未来外生变量。无需添加目标变量 y 和历史变量,因为模型不会使用它们。

futr_df = pd.read_csv('https://datasets-nixtla.s3.amazonaws.com/EPF_FR_BE_futr.csv')
futr_df['ds'] = pd.to_datetime(futr_df['ds'])
futr_df.head()
unique_id ds gen_forecast week_day
0 FR 2016-11-01 00:00:00 49118.0 1
1 FR 2016-11-01 01:00:00 47890.0 1
2 FR 2016-11-01 02:00:00 47158.0 1
3 FR 2016-11-01 03:00:00 45991.0 1
4 FR 2016-11-01 04:00:00 45378.0 1
Important

确保 futr_df 包含整个预测范围的信息。在这个示例中,我们正在预测未来24小时,因此 futr_df 必须为每个时间序列具有24行数据。

最后,使用 predict 方法预测第二天的价格。

Y_hat_df = nf.predict(futr_df=futr_df)
Y_hat_df.head()
c:\Users\ospra\miniconda3\envs\neuralforecast\lib\site-packages\utilsforecast\processing.py:374: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  freq = pd.tseries.frequencies.to_offset(freq)
c:\Users\ospra\miniconda3\envs\neuralforecast\lib\site-packages\utilsforecast\processing.py:428: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  freq = pd.tseries.frequencies.to_offset(freq)
Predicting DataLoader 0: 100%|██████████| 1/1 [00:00<00:00, 46.25it/s]
Predicting DataLoader 0: 100%|██████████| 1/1 [00:00<00:00, 14.09it/s]
c:\Users\ospra\OneDrive\Phd\Repositories\neuralforecast\neuralforecast\core.py:199: FutureWarning: In a future version the predictions will have the id as a column. You can set the `NIXTLA_ID_AS_COL` environment variable to adopt the new behavior and to suppress this warning.
  warnings.warn(
ds NHITS BiTCN
unique_id
BE 2016-11-01 00:00:00 38.138920 40.295403
BE 2016-11-01 01:00:00 34.647514 36.238552
BE 2016-11-01 02:00:00 33.428795 33.724998
BE 2016-11-01 03:00:00 32.428146 31.264389
BE 2016-11-01 04:00:00 31.068453 30.719826
import matplotlib.pyplot as plt

plot_df = df[df['unique_id']=='FR'].tail(24*5).reset_index(drop=True)
Y_hat_df = Y_hat_df.reset_index(drop=False)
Y_hat_df = Y_hat_df[Y_hat_df['unique_id']=='FR']

plot_df = pd.concat([plot_df, Y_hat_df ]).set_index('ds') # 将训练数据框和预测数据框连接起来

plot_df[['y', 'NHITS', 'BiTCN']].plot(linewidth=2)
plt.axvline('2016-11-01', color='red')
plt.ylabel('Price [EUR/MWh]', fontsize=12)
plt.xlabel('Date', fontsize=12)
plt.grid()

总结一下,要将外生变量添加到模型中,请确保遵循以下步骤:

  1. 将时间外生变量作为列添加到主数据框(df)。
  2. 使用static_df数据框添加静态外生变量。
  3. 在相应的模型超参数中指定每个变量的名称。
  4. 如果模型使用未来的外生变量,请将未来数据框(futr_df)传递给predict方法。

参考文献

Give us a ⭐ on Github