间歇性或稀疏数据

在这个笔记本中,我们将为间歇性或稀疏数据实现模型。

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

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

大纲:

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

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

Tip

对于大规模预测,我们建议你查看这个笔记本在Databricks上完成的。

安装库

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

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

pip install statsforecast -U

加载和探索数据

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

pip install datasetsforecast -U
from datasetsforecast.m5 import M5 

加载数据的函数是 M5.load()。它需要以下参数: - directory: (str) 数据将被下载的目录。

该函数返回多个输出,但只需要第一个包含单位销售的数据。

df_total, *_ = M5.load('./data')
df_total.head()
unique_id ds y
0 FOODS_1_001_CA_1 2011-01-29 3.0
1 FOODS_1_001_CA_1 2011-01-30 0.0
2 FOODS_1_001_CA_1 2011-01-31 0.0
3 FOODS_1_001_CA_1 2011-02-01 1.0
4 FOODS_1_001_CA_1 2011-02-02 4.0

从这个数据集中,我们将选择前8个时间序列。您可以通过更改n_series的值来选择任何数量的序列。

n_series = 8 
uids = df_total['unique_id'].unique()[:n_series]
df = df_total.query('unique_id in @uids') 

我们可以使用 StatsForecast 类的 plot 方法来绘制这些序列。该方法有多个参数,生成此笔记本图形所需的参数如下所示。

  • df:一个包含 [unique_id, ds, y] 列的 pandas 数据框。
  • forecasts_df:一个包含 [unique_id, ds] 和模型的 pandas 数据框。
  • plot_random:(bool = True)随机绘制时间序列。
  • max_insample_length:(int)要绘制的训练/样本观察的最大数量。
  • engine:(str = plotly)。用于生成图形的库。它也可以是 matplotlib 用于静态图。
from statsforecast import StatsForecast 
StatsForecast.plot(df, plot_random = False, max_insample_length = 100)

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

df.groupby('unique_id')[['y']].median().query('unique_id in @uids')
y
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

为间歇性数据训练模型

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

dates = df['ds'].unique()[-28:] # 过去28天

train = df.query('ds not in @dates')
test = df.query('ds in @dates')

StatsForecast 提供了多个间歇性数据模型的高效实现。可用模型的完整列表请参见 这里。在本笔记中,我们将使用:

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

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

# 创建一个模型及其实例化参数的列表 
models = [
    ADIDA(), 
    CrostonClassic(), 
    IMAPA(), 
    TSB(alpha_d = 0.2, alpha_p = 0.2)
]

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

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

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

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

horizon = 28 
forecasts = sf.forecast(h=horizon)
forecasts = forecasts.reset_index()
forecasts.head()
unique_id ds ADIDA CrostonClassic IMAPA TSB
0 FOODS_1_001_CA_1 2016-05-23 0.791852 0.898247 0.705835 0.434313
1 FOODS_1_001_CA_1 2016-05-24 0.791852 0.898247 0.705835 0.434313
2 FOODS_1_001_CA_1 2016-05-25 0.791852 0.898247 0.705835 0.434313
3 FOODS_1_001_CA_1 2016-05-26 0.791852 0.898247 0.705835 0.434313
4 FOODS_1_001_CA_1 2016-05-27 0.791852 0.898247 0.705835 0.434313

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

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

绘制预测并计算准确性

我们可以使用上述描述的 plot 生成绘图。

StatsForecast.plot(train, test, plot_random = False, max_insample_length = 100)

要计算预测的准确性,我们将使用平均绝对误差(MAE),即绝对误差的总和除以预测的数量。我们将创建一个函数来计算MAE,为此,我们需要导入numpy

import numpy as np 

def mae(y_hat, y_true):
    return np.mean(np.abs(y_hat-y_true))
y_true = test['y'].values
adida_preds = test['ADIDA'].values
croston_preds = test['CrostonClassic'].values
imapa_preds = test['IMAPA'].values
tsb_preds = test['TSB'].values

print('ADIDA MAE: \t %0.3f' % mae(adida_preds, y_true))
print('Croston Classic MAE: \t %0.3f' % mae(croston_preds, y_true))
print('IMAPA MAE: \t %0.3f' % mae(imapa_preds, y_true))
print('TSB   MAE: \t %0.3f' % mae(tsb_preds, y_true))
ADIDA MAE:   0.949
Croston Classic MAE:     0.944
IMAPA MAE:   0.957
TSB   MAE:   1.023

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

参考文献

Croston, J. D. (1972). 间歇性需求的预测与库存控制. 运筹学研究学会杂志, 23(3), 289-303.

Give us a ⭐ on Github