间歇性或稀疏数据包含很少的非零观测值。这种类型的数据难以预测,因为零值增加了数据中潜在模式的不确定性。此外,一旦出现非零观测值,其大小可能会有相当大的变化。间歇性时间序列在许多行业中很常见,包括金融、零售、运输和能源。鉴于此类序列的普遍性,已经开发出特殊方法来预测它们。第一种方法来自 Croston (1972),随后出现了几种变体和不同的聚合框架。

StatsForecast 实现了多种模型来预测间歇性时间序列。在本教程结束时,您将对这些模型及其使用方法有一个很好的了解。

大纲

  1. 安装库
  2. 加载并探索数据
  3. 训练间歇性数据模型
  4. 绘制预测结果并计算精度

提示

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

提示

对于大规模预测,我们建议您查看在 Databricks 上完成的 此 Notebook

安装库

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

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

pip install statsforecast -U

加载并探索数据

在此示例中,我们将使用 M5 Competition 数据集的子集。每个时间序列表示特定产品在给定 Walmart 商店的单位销售额。在此层面(产品-商店),大部分数据是间歇性的。我们首先需要导入数据。

import pandas as pd
uids = [
    'FOODS_1_001_CA_1',
    'FOODS_1_001_CA_2',
    'FOODS_1_001_CA_3',
    'FOODS_1_001_CA_4',
    'FOODS_1_001_TX_1',
    'FOODS_1_001_TX_2',
    'FOODS_1_001_TX_3',
    'FOODS_1_001_WI_1',
]
df = pd.read_parquet(
    'https://datasets-nixtla.s3.amazonaws.com/m5_y.parquet',
    filters=[('unique_id', 'in', uids)],
)

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

  • df: 一个 pandas 数据框,包含列 [unique_id, ds, y]。
  • forecasts_df: 一个 pandas 数据框,包含列 [unique_id, ds] 和模型。
  • plot_random: 随机绘制时间序列。
  • max_insample_length: 要绘制的最大训练/样本内观测数量。
  • engine: 用于生成图的库。对于静态图,也可以是 matplotlib
from utilsforecast.plotting import plot_series
plot_series(df, plot_random=False, max_insample_length=100)

这里我们只绘制了最后 100 个观测值,但我们可以通过移除 max_insample_length 来可视化完整的历史记录。从这些图中,我们可以确认数据确实是间歇性的,因为它有多个销售为零的时期。事实上,除了一个情况外,中位数都是零。

df.groupby('unique_id', observed=True)['y'].median()
unique_id
FOODS_1_001_CA_1    0.0
FOODS_1_001_CA_2    1.0
FOODS_1_001_CA_3    0.0
FOODS_1_001_CA_4    0.0
FOODS_1_001_TX_1    0.0
FOODS_1_001_TX_2    0.0
FOODS_1_001_TX_3    0.0
FOODS_1_001_WI_1    0.0
Name: y, dtype: float32

训练间歇性数据模型

在训练任何模型之前,我们需要将数据分成训练集和测试集。M5 Competition 使用最后 28 天作为测试集,所以我们也这样做。

valid_start = df['ds'].unique()[-28]

train = df[df['ds'] < valid_start]
test = df[df['ds'] >= valid_start]

StatsForecast 高效地实现了多种用于间歇性数据的模型。可用的完整模型列表在此。在本 Notebook 中,我们将使用:

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

from statsforecast import StatsForecast
from statsforecast.models import (
    ADIDA,
    CrostonClassic, 
    IMAPA, 
    TSB
)

# Create a list of models and instantiation parameters 
models = [
    ADIDA(), 
    CrostonClassic(), 
    IMAPA(), 
    TSB(alpha_d = 0.2, alpha_p = 0.2)
]

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

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

现在我们准备生成预测结果。为此,我们将使用 forecast 方法,该方法需要预测范围(在本例中为 28 天)作为参数。

StatsForecast 中当前可用于间歇性序列的模型只能生成点预测。如果需要预测区间,则应使用概率模型

horizon = 28 
forecasts = sf.forecast(df=train, h=horizon)
forecasts.head()
unique_iddsADIDACrostonClassicIMAPATSB
0FOODS_1_001_CA_12016-05-230.7918520.8982470.7058350.434313
1FOODS_1_001_CA_12016-05-240.7918520.8982470.7058350.434313
2FOODS_1_001_CA_12016-05-250.7918520.8982470.7058350.434313
3FOODS_1_001_CA_12016-05-260.7918520.8982470.7058350.434313
4FOODS_1_001_CA_12016-05-270.7918520.8982470.7058350.434313

最后,我们将预测结果与实际值合并。

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

绘制预测结果并计算精度

我们可以使用上面描述的 plot_series 函数生成图。

plot_series(train, test, plot_random=False, max_insample_length=100)

为了计算预测结果的精度,我们将使用平均绝对误差 (MAE),它是绝对误差之和除以预测数量。

from utilsforecast.evaluation import evaluate
from utilsforecast.losses import mae
evaluate(test, metrics=[mae], agg_fn='mean')
metricADIDACrostonClassicIMAPATSB
0mae0.9487290.9440710.9572561.023126

因此,平均而言,预测结果偏差为一个单位。

参考资料

Croston, J. D. (1972). Forecasting and stock control for intermittent demands. Journal of the Operational Research Society, 23(3), 289-303.