在使用神经网络预测方法时,缩放时间序列数据是一个重要的预处理步骤,原因如下:

  1. 收敛速度:当特征处于相似的尺度时,神经网络预测模型往往收敛得更快。
  2. 避免梯度消失或梯度爆炸:一些架构,例如循环神经网络 (RNN),对输入数据的尺度很敏感。如果输入值过大,可能导致梯度爆炸,即梯度变得过大,模型变得不稳定。反之,非常小的输入值可能导致梯度消失,即训练期间权重更新可以忽略不计,训练无法收敛。
  3. 确保尺度一致:神经网络预测模型对任务中的所有时间序列共享全局参数。在时间序列尺度不同的情况下,缩放可以确保没有任何特定的时间序列主导学习过程。
  4. 提高泛化能力:尺度一致的时间序列可以产生更平滑的损失曲面。此外,缩放有助于使输入数据的分布均匀化,这也可以通过避免超出范围的值来提高泛化能力。

Neuralforecast 库集成了两种时间尺度缩放方法:

  • 时间序列缩放:在使用训练集中的所有数据训练模型之前,对每个时间序列进行缩放。这是通过使用 Neuralforecast 核心类的 local_scaler_type 参数来完成的。
  • 窗口缩放 (TemporalNorm):在每个训练迭代中,对批量中每个元素的每个输入窗口单独进行缩放。这是通过使用每个模型类的 scaler_type 参数来完成的。

在本笔记本中,我们将演示如何在电力价格预测 (EPF) 任务中使用这两种方法缩放时间序列数据。

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

1. 安装 Neuralforecast

!pip install neuralforecast
!pip install hyperopt

2. 加载数据

df 数据框包含用于训练模型的目标变量和外部变量的过去信息。unique_id 列标识市场,ds 包含日期戳,y 包含电力价格。对于未来变量,我们包含了电力产量的预测 (gen_forecast) 和一周中的某天 (week_day)。电力系统的需求和供应都会显著影响价格,在模型中包含这些变量可以极大地提高性能,正如我们在 Olivares 等人 (2022) 中所示。

futr_df 数据框包含我们想要预测的未来外部变量的信息(在本例中,是训练数据集 df 结束后的 24 小时)。

import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv(
    'https://datasets-nixtla.s3.amazonaws.com/EPF_FR_BE.csv',
    parse_dates=['ds'],
)
futr_df = pd.read_csv(
    'https://datasets-nixtla.s3.amazonaws.com/EPF_FR_BE_futr.csv',
    parse_dates=['ds'],
)
df.head()
unique_iddsygen_forecastsystem_loadweek_day
0FR2015-01-01 00:00:0053.4876905.074812.03
1FR2015-01-01 01:00:0051.9375492.071469.03
2FR2015-01-01 02:00:0048.7674394.069642.03
3FR2015-01-01 03:00:0042.2772639.066704.03
4FR2015-01-01 04:00:0038.4169347.065051.03

我们可以看到 y 和外部变量的尺度差异很大。接下来,我们将展示两种数据缩放方法。

3. 使用 Neuralforecast 类进行时间序列缩放

最广泛使用的时间序列缩放方法之一是将其视为预处理步骤,其中每个时间序列和时间外部变量根据其在训练集中的全部信息进行缩放。然后,在缩放后的数据上训练模型。

为了简化流程,我们在 Neuralforecast 类中添加了缩放功能。在通过 fitcross_validation 训练模型之前,每个时间序列都会被缩放,并且缩放统计数据会被存储。然后,该类使用存储的统计数据将预测结果缩放回原始尺度,然后再返回预测结果。

3.a. 实例化模型和 Neuralforecast

在本例中,我们将使用 TimesNet 模型,该模型最近由 Wu, Haixu 等人 (2022) 提出。首先使用所需的参数实例化模型。

import logging

from neuralforecast.models import TimesNet
from neuralforecast.core import NeuralForecast
logging.getLogger("pytorch_lightning").setLevel(logging.WARNING)
horizon = 24 # day-ahead daily forecast
model = TimesNet(h = horizon,                                   # Horizon
                 input_size = 5*horizon,                        # Length of input window
                 max_steps = 100,                               # Training iterations
                 top_k = 3,                                     # Number of periods (for FFT).
                 num_kernels = 3,                               # Number of kernels for Inception module
                 batch_size = 2,                                # Number of time series per batch
                 windows_batch_size = 32,                       # Number of windows per batch
                 learning_rate = 0.001,                         # Learning rate
                 futr_exog_list = ['gen_forecast', 'week_day'], # Future exogenous variables
                 scaler_type = None)                            # We use the Core scaling method
Seed set to 1

通过实例化一个 NeuralForecast 对象并使用 fit 方法来拟合模型。local_scaler_type 参数用于指定要使用的缩放类型。在本例中,我们将使用 standard,它将数据缩放到零均值和单位方差。其他支持的缩放器包括 minmaxrobustrobust-iqrminmaxboxcox

nf = NeuralForecast(models=[model], freq='h', local_scaler_type='standard')
nf.fit(df=df)
Sanity Checking: |                                                                                            …
Training: |                                                                                                   …
Validation: |                                                                                                 …

3.b 预测和绘图

最后,使用 predict 方法预测下一天的价格。Neuralforecast 类处理反归一化,预测结果以原始尺度返回。

Y_hat_df = nf.predict(futr_df=futr_df)
Y_hat_df.head()
Predicting: |                                                                                                 …
unique_iddsTimesNet
0BE2016-11-01 00:00:0039.523182
1BE2016-11-01 01:00:0033.386608
2BE2016-11-01 02:00:0027.978468
3BE2016-11-01 03:00:0028.143955
4BE2016-11-01 04:00:0032.332230
from utilsforecast.plotting import plot_series
plot_series(df, Y_hat_df, max_insample_length=24*5)

重要

在返回最终预测结果之前,由 Neuralforecast 类执行反向缩放。因此,使用 Auto 模型进行的超参数选择以及用于提前停止或模型选择的验证损失都是在缩放后的数据上进行的。使用 Neuralforecast 类进行不同类型的缩放无法与 Auto 模型自动进行比较。

4. 训练期间的时间窗口归一化

时间归一化在窗口级别对批处理中的每个实例分别进行缩放。在每个训练迭代中,对批处理中的每个窗口进行操作,包括目标变量和时间外部协变量。有关更多详细信息,请参阅 Olivares 等人 (2023)https://nixtla.github.io/neuralforecast/common.scalers.html

4.a. 实例化模型和 Neuralforecast

时间归一化由 scaler_type 参数指定。目前,它仅支持基于窗口的模型(NHITSNBEATSMLPTimesNet 和所有 Transformer 模型)。在本例中,我们使用 TimesNet 模型和 robust 缩放器,后者由 Wu, Haixu 等人 (2022) 最近提出。首先使用所需的参数实例化模型。

请访问 https://nixtla.github.io/neuralforecast/common.scalers.html 查看支持的缩放器的完整列表。

horizon = 24 # day-ahead daily forecast
model = TimesNet(h = horizon,                                  # Horizon
                 input_size = 5*horizon,                       # Length of input window
                 max_steps = 100,                              # Training iterations
                 top_k = 3,                                    # Number of periods (for FFT).
                 num_kernels = 3,                              # Number of kernels for Inception module
                 batch_size = 2,                               # Number of time series per batch
                 windows_batch_size = 32,                      # Number of windows per batch
                 learning_rate = 0.001,                        # Learning rate
                 futr_exog_list = ['gen_forecast','week_day'], # Future exogenous variables
                 scaler_type = 'robust')                       # Robust scaling
Seed set to 1

通过实例化一个 NeuralForecast 对象并使用 fit 方法来拟合模型。请注意,local_scaler_type 默认为 None,以避免在训练前对数据进行缩放。

nf = NeuralForecast(models=[model], freq='h')
nf.fit(df=df)
Sanity Checking: |                                                                                            …
Training: |                                                                                                   …
Validation: |                                                                                                 …

4.b 预测和绘图

最后,使用 predict 方法预测下一天的价格。预测结果以原始尺度返回。

Y_hat_df = nf.predict(futr_df=futr_df)
Y_hat_df.head()
Predicting: |                                                                                                 …
unique_iddsTimesNet
0BE2016-11-01 00:00:0037.624653
1BE2016-11-01 01:00:0033.069824
2BE2016-11-01 02:00:0030.623751
3BE2016-11-01 03:00:0028.773439
4BE2016-11-01 04:00:0030.689444
plot_series(df, Y_hat_df, max_insample_length=24*5)

重要

对于大多数应用,带有时间归一化(第 4 节)的模型比时间序列缩放(第 3 节)的模型产生了更准确的预测。然而,时间归一化模型丢失了不同窗口之间的相对水平信息。在某些情况下,这种时间序列内的全局信息至关重要,例如当一个外部变量包含药物剂量时。在这些情况下,更推荐使用时间序列缩放(第 3 节)。

参考文献