先决条件

本教程假定您对 StatsForecast 有基本了解。如需一个简单示例,请访问快速入门

简介

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

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

StatsForecast 提供了许多可以生成点预测的模型。它也包含可以生成相同点预测及其预测区间的概率模型。这些模型是随机数据生成过程,可以产生完整的预测分布。在本教程结束时,您将对 StatsForecast 中可用的概率模型有很好的理解,并能够使用它们生成点预测和预测区间。此外,您还将学习如何使用历史数据、点预测和预测区间生成图表。

重要提示

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

警告

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

目录

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

提示

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

安装库

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

使用 pip install statsforecast 安装所需的包

加载和探索数据

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

import pandas as pd
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').rename(columns={'y': 'y_test'})
train.head()
unique_iddsy
0H11605.0
1H12586.0
2H13586.0
3H14559.0
4H15511.0
test.head()
unique_iddsy_test
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')

我们可以使用 StatsForecast 类中的 statsforecast.plot 方法绘制这些序列。此方法有多个参数,下文解释了在此 notebook 中生成图表所需的参数。

  • df: 一个包含列 [unique_id, ds, y] 的 pandas 数据帧。
  • forecasts_df: 一个包含列 [unique_id, ds] 和模型的 pandas 数据帧。
  • plot_random: bool = True。随机绘制时间序列。
  • models: List[str]。一个包含我们想要绘制的模型列表。
  • level: List[float]。一个包含我们想要绘制的预测区间列表。
  • engine: str = plotly。也可以是 matplotlibplotly 生成交互式图表,而 matplotlib 生成静态图表。
from statsforecast import StatsForecast
StatsForecast.plot(train, test, plot_random=False)

训练模型

StatsForecast 可以有效地在不同时间序列上训练多种模型。这些模型中的大多数都可以生成概率预测,这意味着它们既可以生成点预测,也可以生成预测区间。

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

要使用这些模型,我们首先需要从 statsforecast.models 中导入它们,然后实例化它们。考虑到我们正在处理每小时数据,对于需要此参数的模型,我们需要设置 seasonal_length=24

from statsforecast.models import (
    AutoETS, 
    HistoricAverage, 
    Naive, 
    RandomWalkWithDrift, 
    SeasonalNaive
)
# Create a list of models and instantiation parameters 
models = [
    AutoETS(season_length=24),
    HistoricAverage(), 
    Naive(), 
    RandomWalkWithDrift(), 
    SeasonalNaive(season_length=24)
]

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

  • df: 包含训练数据的数据帧。
  • models: 在上一步中定义的模型列表。
  • freq: 一个字符串,指示数据的频率。请参阅pandas 可用的频率
  • n_jobs: 一个整数,表示并行处理中使用的作业数。使用 -1 选择所有核心。
sf = StatsForecast( 
    models=models, 
    freq=1,
    n_jobs=-1
)

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

  • h: 一个整数,表示预测范围。在本例中,我们将预测未来 48 小时。
  • level: 一个浮点数列表,表示预测区间的置信水平。例如,level=[95] 表示值范围应以 95% 的概率包含实际未来值。
levels = [80, 90, 95, 99] # confidence levels of the prediction intervals 

forecasts = sf.forecast(df=train, h=48, level=levels)
forecasts.head()
unique_iddsAutoETSAutoETS-lo-99AutoETS-lo-95AutoETS-lo-90AutoETS-lo-80AutoETS-hi-80AutoETS-hi-90AutoETS-hi-95RWD-hi-99SeasonalNaiveSeasonalNaive-lo-80SeasonalNaive-lo-90SeasonalNaive-lo-95SeasonalNaive-lo-99SeasonalNaive-hi-80SeasonalNaive-hi-90SeasonalNaive-hi-95SeasonalNaive-hi-99
0H1701631.889598533.371822556.926831568.978861582.874079680.905116694.800335706.852365789.416619691.0613.351903591.339747572.247484534.932739768.648097790.660253809.752516847.067261
1H1702559.750830460.738592484.411824496.524343510.489302609.012359622.977317635.089836833.254152618.0540.351903518.339747499.247484461.932739695.648097717.660253736.752516774.067261
2H1703519.235476419.731233443.522100455.694808469.729161568.741792582.776145594.948853866.990616563.0485.351903463.339747444.247484406.932739640.648097662.660253681.752516719.067261
3H1704486.973364386.979536410.887460423.120060437.223465536.723263550.826668563.059268895.510095529.0451.351903429.339747410.247484372.932739606.648097628.660253647.752516685.067261
4H1705464.697366364.216339388.240749400.532950414.705071514.689661528.861782541.153983920.702904504.0426.351903404.339747385.247484347.932739581.648097603.660253622.752516660.067261

现在我们将把预测结果及其预测区间与测试集合并。这将使我们能够生成每个概率模型的图表。

test = test.merge(forecasts, how='left', on=['unique_id', 'ds'])

绘制预测区间

要绘制点和预测区间,我们将再次使用 statsforecast.plot 方法。请注意,现在我们还需要指定要绘制的模型和置信水平。

AutoETS

sf.plot(train, test, plot_random=False, models=['AutoETS'], level=levels)

历史平均

sf.plot(train, test, plot_random=False, models=['HistoricAverage'], level=levels)

Naive

sf.plot(train, test, plot_random=False, models=['Naive'], level=levels)

带漂移的随机游走

sf.plot(train, test, plot_random=False, models=['RWD'], level=levels)

季节性朴素法

sf.plot(train, test, plot_random=False, models=['SeasonalNaive'], level=levels)

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

参考文献

Rob J. Hyndman 和 George Athanasopoulos (2018)。“预测原则与实践,统计预测视角”.