前提条件

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

引言

生成预测时,我们通常会得到一个单一的值,称为点预测。然而,这个值并没有告诉我们与预测相关的不确定性。为了衡量这种不确定性,我们需要预测区间

预测区间是预测值在给定概率下可能落入的范围。因此,一个 95% 的预测区间应包含一个范围,其中包含实际未来值的概率为 95%。概率预测旨在生成完整的预测分布。另一方面,点预测通常返回所述分布的平均值或中位数。然而,在现实世界中,最好不仅预测最可能的未来结果,还要预测许多替代结果。

使用MLForecast,您可以训练 sklearn 模型来生成点预测。它还利用 ConformalPrediction 来生成相同的点预测并为其添加预测区间。在本教程结束时,您将很好地了解如何为时间序列预测中的 sklearn 模型添加概率区间。此外,您还将学习如何使用历史数据、点预测和预测区间生成图表。

重要

尽管这些术语经常混淆,但预测区间与置信区间不同。

警告

实际上,大多数预测区间都太窄,因为模型没有考虑到所有不确定性来源。有关此问题的讨论可在此处找到。

大纲

  1. 安装库
  2. 加载和探索数据
  3. 训练模型
  4. 绘制预测区间

提示

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

安装库

使用 pip install mlforecast utilsforecast 安装必需的软件包

加载和探索数据

在本例中,我们将使用M4 竞赛中的每小时数据集。我们首先需要从 URL 下载数据,然后将其加载为 pandas dataframe。请注意,我们将分别加载训练数据和测试数据。我们还将把测试数据的 y 列重命名为 y_test

import pandas as pd
from utilsforecast.plotting import plot_series
train = pd.read_csv('https://auto-arima-results.s3.amazonaws.com/M4-Hourly.csv')
test = pd.read_csv('https://auto-arima-results.s3.amazonaws.com/M4-Hourly-test.csv')
train.head()
unique_iddsy
0H11605.0
1H12586.0
2H13586.0
3H14559.0
4H15511.0
test.head()
unique_iddsy
0H1701619.0
1H1702565.0
2H1703532.0
3H1704495.0
4H1705481.0

由于此 Notebook 的目标是生成预测区间,我们将仅使用数据集的前 8 个序列以减少总计算时间。

n_series = 8 
uids = train['unique_id'].unique()[:n_series] # select first n_series of the dataset
train = train.query('unique_id in @uids')
test = test.query('unique_id in @uids')

我们可以使用utilsforecast库中的 plot_series 函数绘制这些序列。此函数有多个参数,本 Notebook 中生成图表所需的参数如下所示。

  • df: 一个包含列 [unique_id, ds, y] 的 pandas dataframe。
  • forecasts_df: 一个包含列 [unique_id, ds] 和模型的 pandas dataframe。
  • plot_random: bool = True。随机绘制时间序列。
  • models: List[str]。包含我们要绘制的模型的列表。
  • level: List[float]。包含我们要绘制的预测区间的列表。
  • engine: str = matplotlib。也可以是 plotlyplotly 生成交互式图表,而 matplotlib 生成静态图表。
fig = plot_series(train, test.rename(columns={'y': 'y_test'}), models=['y_test'], plot_random=False)

训练模型

MLForecast 可以高效地在不同的时间序列上训练遵循 sklearn 语法(fitpredict)的多个模型。

在本例中,我们将使用以下 sklearn 基线模型

要使用这些模型,我们首先需要从 sklearn 导入它们,然后实例化它们。

from mlforecast import MLForecast
from mlforecast.target_transforms import Differences
from mlforecast.utils import PredictionIntervals
from sklearn.linear_model import Lasso, LinearRegression, Ridge
from sklearn.neighbors import KNeighborsRegressor
from sklearn.neural_network import MLPRegressor
# Create a list of models and instantiation parameters 
models = [
    KNeighborsRegressor(),
    Lasso(),
    LinearRegression(),
    MLPRegressor(),
    Ridge(),
]

要实例化一个新的 MLForecast 对象,我们需要以下参数

  • models: 上一步中定义的模型列表。
  • target_transforms: 在计算特征之前应用于目标变量的变换。这些变换在预测步骤中会恢复。
  • lags: 用作特征的目标变量滞后值。
mlf = MLForecast(
    models=[Ridge(), Lasso(), LinearRegression(), KNeighborsRegressor(), MLPRegressor(random_state=0)],
    freq=1,
    target_transforms=[Differences([1])],
    lags=[24 * (i+1) for i in range(7)],
)

现在我们准备生成点预测和预测区间。为此,我们将使用 fit 方法,该方法接受以下参数:

  • data: 长格式的序列数据。
  • id_col: 标识每个序列的列。在本例中为 unique_id
  • time_col: 标识每个时间步的列,其值可以是时间戳或整数。在本例中为 ds
  • target_col: 包含目标变量的列。在本例中为 y
  • prediction_intervals: 一个 PredicitonIntervals 类。该类接受两个参数:n_windowshn_windows 表示用于校准区间的交叉验证窗口数量,h 是预测范围。该策略将针对每个预测范围步骤调整区间,从而导致每个步骤的宽度不同。
mlf.fit(
    train,
    prediction_intervals=PredictionIntervals(n_windows=10, h=48),
);

拟合模型后,我们将调用 predict 方法生成带预测区间的预测结果。该方法接受以下参数:

  • horizon: 表示预测范围的整数。在本例中,我们将预测未来 48 小时。
  • level: 一个浮点数列表,表示预测区间的置信水平。例如,level=[95] 意味着值范围应包含实际未来值,概率为 95%。
levels = [50, 80, 95]
forecasts = mlf.predict(48, level=levels)
forecasts.head()
unique_iddsRidgeLassoLinearRegressionKNeighborsRegressorMLPRegressorRidge-lo-95Ridge-lo-80Ridge-lo-50KNeighborsRegressor-lo-50KNeighborsRegressor-hi-50KNeighborsRegressor-hi-80KNeighborsRegressor-hi-95MLPRegressor-lo-95MLPRegressor-lo-80MLPRegressor-lo-50MLPRegressor-hi-50MLPRegressor-hi-80MLPRegressor-hi-95
0H1701612.418170612.418079612.418170615.2612.651532590.473256594.326570603.409944609.45620.95627.20631.310584.736193591.084898597.462107627.840957634.218166640.566870
1H1702552.309298552.308073552.309298551.6548.791801498.721501518.433843532.710850535.85567.35569.16597.525497.308756500.417799515.452396582.131207597.165804600.274847
2H1703494.943384494.943367494.943384509.6490.226796448.253304463.266064475.006125492.70526.50530.92544.180424.587658436.042788448.682502531.771091544.410804555.865935
3H1704462.815779462.815363462.815779474.6459.619069409.975219422.243593436.128272451.80497.40510.26525.500379.291083392.580306413.353178505.884959526.657832539.947054
4H1705440.141034440.140586440.141034451.6438.091712377.999588392.523016413.474795427.40475.80488.96503.945348.618034362.503767386.303325489.880099513.679657527.565389
test = test.merge(forecasts, how='left', on=['unique_id', 'ds'])

绘制预测区间

为了绘制点预测和预测区间,我们将再次使用 plot_series 函数。请注意,现在我们还需要指定要绘制的模型和级别。

KNeighborsRegressor

fig = plot_series(
    train, 
    test, 
    plot_random=False, 
    models=['KNeighborsRegressor'], 
    level=levels, 
    max_insample_length=48
)

Lasso

fig = plot_series(
    train, 
    test, 
    plot_random=False, 
    models=['Lasso'],
    level=levels, 
    max_insample_length=48
)

LineaRegression

fig = plot_series(
    train, 
    test, 
    plot_random=False, 
    models=['LinearRegression'],
    level=levels, 
    max_insample_length=48
)

MLPRegressor

fig = plot_series(
    train, 
    test, 
    plot_random=False, 
    models=['MLPRegressor'],
    level=levels, 
    max_insample_length=48
)

Ridge

fig = plot_series(
    train, 
    test, 
    plot_random=False, 
    models=['Ridge'],
    level=levels, 
    max_insample_length=48
)

从这些图表可以看出,每个预测结果的不确定性因所使用的模型而异。对于相同的时间序列,一个模型预测的可能未来值范围可能比其他模型更广。

参考文献