前提条件

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

引言

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

MLForecast 提供了一种快速易用的时间序列交叉验证实现。这种实现使得交叉验证成为一种高效的操作,从而减少了时间消耗。在本 notebook 中,我们将使用 M4 竞赛小时数据集的子集来演示。

大纲

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

提示

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

安装库

我们假定您已安装 MLForecast。如果尚未安装,请查阅此指南了解如何安装 MLForecast

使用 pip install mlforecast 安装必要的包。

import pandas as pd 

from utilsforecast.plotting import plot_series

from mlforecast import MLForecast # required to instantiate MLForecast object and use cross-validation method

加载并探索数据

如引言所述,我们将使用 M4 竞赛小时数据集。我们将首先使用 pandas 从 URL 导入数据。

Y_df = pd.read_csv('https://datasets-nixtla.s3.amazonaws.com/m4-hourly.csv') # load the data 
Y_df.head()
unique_iddsy
0H11605.0
1H12586.0
2H13586.0
3H14559.0
4H15511.0

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

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

此示例中的数据已采用此格式,因此无需进行任何更改。

我们可以使用以下函数绘制我们将处理的时间序列。

fig = plot_series(Y_df, max_ids=4, plot_random=False, max_insample_length=24 * 14)

定义预测对象

在本示例中,我们将使用 LightGBM。我们首先需要导入它,然后实例化一个新的 MLForecast 对象。

在此示例中,我们仅使用 differenceslags 来生成特征。请参阅完整文档以查看所有可用特征。

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

import lightgbm as lgb
from mlforecast.target_transforms import Differences
models = [lgb.LGBMRegressor(verbosity=-1)]

mlf = MLForecast(
    models=models, 
    freq=1,# our series have integer timestamps, so we'll just add 1 in every timeste, 
    target_transforms=[Differences([24])],
    lags=range(1, 25)
)

执行时间序列交叉验证

实例化 MLForecast 对象后,我们可以使用 cross_validation 方法

对于此特定示例,我们将使用 3 个 24 小时窗口。

cv_df = mlf.cross_validation(
    df=Y_df,
    h=24,
    n_windows=3,
)

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

  • unique_id:标识每个时间序列。
  • ds:日期戳或时间索引。
  • cutoffn_windows 的最后一个日期戳或时间索引。
  • y:真实值
  • "model":包含模型名称和拟合值的列。
cv_df.head()
unique_iddscutoffyLGBMRegressor
0H1677676691.0673.703191
1H1678676618.0552.306270
2H1679676563.0541.778027
3H1680676529.0502.778027
4H1681676504.0480.778027

现在我们将绘制每个截止期的预测结果。

import matplotlib.pyplot as plt
def plot_cv(df, df_cv, uid, fname, last_n=24 * 14):
    cutoffs = df_cv.query('unique_id == @uid')['cutoff'].unique()
    fig, ax = plt.subplots(nrows=len(cutoffs), ncols=1, figsize=(14, 6), gridspec_kw=dict(hspace=0.8))
    for cutoff, axi in zip(cutoffs, ax.flat):
        df.query('unique_id == @uid').tail(last_n).set_index('ds').plot(ax=axi, title=uid, y='y')
        df_cv.query('unique_id == @uid & cutoff == @cutoff').set_index('ds').plot(ax=axi, title=uid, y='LGBMRegressor')
    fig.savefig(fname, bbox_inches='tight')
    plt.close()
plot_cv(Y_df, cv_df, 'H1', '../../figs/cross_validation__predictions.png')

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

评估结果

现在我们可以使用适当的精度指标计算预测的精度。在此,我们将使用均方根误差 (RMSE)。为此,我们可以使用 utilsforecast,这是 Nixtla 开发的一个 Python 库,其中包含计算 RMSE 的函数。

from utilsforecast.evaluation import evaluate
from utilsforecast.losses import rmse
cv_rmse = evaluate(
    cv_df.drop(columns='cutoff'),
    metrics=[rmse],
    agg_fn='mean',
)
print(f"RMSE using cross-validation: {cv_rmse['LGBMRegressor'].item():.1f}")
RMSE using cross-validation: 269.0

此度量标准应更好地反映我们模型的预测能力,因为它使用了不同的时间段来测试其精度。

参考文献

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