交叉验证

在这个例子中,我们将实现时间序列交叉验证来评估模型的性能。

本教程假设您对StatsForecast有基本的了解。要查看一个最简单的例子,请访问快速入门

介绍

时间序列交叉验证是一种评估模型在过去表现的方法。它通过在历史数据上定义一个滑动窗口,并预测其后的时间段来实现。

Statsforecast 提供了一种快速且易于使用的时间序列交叉验证实现。这个实现将交叉验证转变为分布式操作,从而减少了时间消耗。在这个笔记本中,我们将其应用于 M4 Competition 每小时数据集的一个子集。

大纲:

  1. 安装库
  2. 加载和探索数据
  3. 训练模型
  4. 执行时间序列交叉验证
  5. 评估结果
Tip

您可以使用Colab互动运行此Notebook 在Colab中打开

安装库

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

使用 pip install statsforecast 安装所需的包。

pip install statsforecast 
from statsforecast import StatsForecast # 需要实例化StastForecast对象并使用交叉验证方法 

加载和探索数据

正如在介绍中所述,我们将使用M4竞赛的小时数据集。我们将首先使用pandas从一个URL导入数据。

import pandas as pd 

Y_df = pd.read_parquet('https://datasets-nixtla.s3.amazonaws.com/m4-hourly.parquet') # 加载数据 
Y_df.head() 
unique_id ds y
0 H1 1 605.0
1 H1 2 586.0
2 H1 3 586.0
3 H1 4 559.0
4 H1 5 511.0

StatsForecast 的输入是一个 长格式 的数据框,包含三列:unique_iddsy

  • unique_id(字符串、整数或类别)表示序列的标识符。
  • ds(日期戳或整数)列应为整数索引时间或格式为 YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS 的日期戳。
  • y(数值型)表示我们希望预测的测量值。

该示例中的数据已经具备这种格式,因此不需要进行更改。

为了将执行此笔记本所需的时间保持在最小,我们将仅使用数据中的一个时间序列,即 unique_id == 'H1' 的那个。然而,您可以使用任意多个时间序列,不需要对代码进行其他更改。

df = Y_df[Y_df['unique_id'] == 'H1'] # 选择时间序列 

我们可以使用 StatsForecast.plot 方法绘制我们将要使用的时间序列。

StatsForecast.plot(df)

训练模型

在这个例子中,我们将使用 StastForecast AutoETS。首先,我们需要从 statsforecast.models 导入它,然后我们需要实例化一个新的 StatsForecast 对象。

StatsForecast 对象具有以下参数:

  • models: 模型列表。从 模型 中选择您想要的模型并导入。
  • freq: 一个字符串,指示数据的频率。请参见 pandas 可用的频率
  • n_jobs: n_jobs: int,进行并行处理时使用的作业数量,使用 -1 表示使用所有核心。

任何设置都将传递给构造函数。然后您调用其 fit 方法并传入历史数据框 df

from statsforecast.models import AutoETS

models = [AutoETS(season_length = 24)]

sf = StatsForecast(
    df = df, 
    models = models, 
    freq = 'H', 
    n_jobs = -1
)

执行时间序列交叉验证

一旦实例化了StatsForecast对象,我们可以使用cross_validation方法,该方法接受以下参数:

  • df:采用StatsForecast格式的训练数据框
  • h(整数):表示将要预测的未来h个步骤
  • step_size(整数):每个窗口之间的步长,意味着您希望多频繁地运行预测过程。
  • n_windows(整数):用于交叉验证的窗口数量,意味着您希望评估过去的预测过程的数量。

对于这个特定的例子,我们将使用3个24小时的窗口。

crossvalidation_df = sf.cross_validation(
    df = df,
    h = 24,
    step_size = 24,
    n_windows = 3
  )

crossvaldation_df对象是一个新的数据框,包含以下列:

  • unique_id: 索引。如果您不喜欢使用索引,可以运行crossvalidation_df.resetindex()
  • ds: 日期戳或时间索引
  • cutoff: n_windows的最后一个日期戳或时间索引。
  • y: 真实值
  • "model": 包含模型名称和拟合值的列。
crossvalidation_df.head()
ds cutoff y AutoETS
unique_id
H1 677 676 691.0 677.761047
H1 678 676 618.0 607.817871
H1 679 676 563.0 569.437744
H1 680 676 529.0 537.340027
H1 681 676 504.0 515.571106

我们现在将绘制每个截止期的预测。为了使图形更清晰,我们将重新命名每个时期的实际值。

crossvalidation_df.rename(columns = {'y' : 'actual'}, inplace = True) # 重命名实际值 

cutoff = crossvalidation_df['cutoff'].unique()

for k in range(len(cutoff)): 
    cv = crossvalidation_df[crossvalidation_df['cutoff'] == cutoff[k]]
    StatsForecast.plot(df, cv.loc[:, cv.columns != 'cutoff'])

请注意,在每个截止期,我们仅使用该期间之前的数据 y 来生成未来 24 小时的预测。

评估结果

我们现在可以使用适当的准确性指标计算预测的准确性。在这里,我们将使用均方根误差 (RMSE)。 为此,我们首先需要安装.datasetsforecast,这是Nixtla开发的一个Python库,其中包含计算RMSE的函数。

pip install datasetsforecast
from datasetsforecast.losses import rmse  

计算RMSE的函数需要两个参数:

  1. 实际值。
  2. 预测值,在本例中为AutoETS
rmse = rmse(crossvalidation_df['actual'], crossvalidation_df['AutoETS'])
print("RMSE using cross-validation: ", rmse)
RMSE using cross-validation:  33.90342

这个测量应该更好地反映我们模型的预测能力,因为它使用不同的时间段来测试其准确性。

Tip

交叉验证在比较多个模型时特别有用。这里有一个示例,展示了多个模型和时间序列的应用。

参考文献

Rob J. Hyndman 和 George Athanasopoulos (2018). “预测原则与实践,时间序列交叉验证”

Give us a ⭐ on Github