协调快速入门

分层协调的最小示例

大量的时间序列按不同聚合层次组织成结构,通常需要它们的预测遵循聚合约束,这就带来了创建能够进行一致性预测的新算法的挑战。

HierarchicalForecast 包提供了一系列经典层级调和的层级预测算法的 Python 实现。

在本笔记本中,我们将展示如何使用 StatsForecast 库生成基本预测,并使用 HierarchicalForecast 包进行层级调和。

您可以使用Google Colab通过CPU或GPU运行这些实验。

在Colab中打开

1. 库

%%capture
# !pip 安装 hierarchicalforecast
# !pip 安装 -U numba statsforecast datasetsforecast

2. 加载数据

在这个例子中,我们将使用 TourismSmall 数据集。以下单元获取层次结构中不同级别的时间序列、汇总矩阵 S,该矩阵从底层层次结构恢复完整数据集,以及每个层次的索引,称为 tags

import numpy as np
import pandas as pd

from datasetsforecast.hierarchical import HierarchicalData, HierarchicalInfo
group_name = 'TourismSmall'
group = HierarchicalInfo.get_group(group_name)
Y_df, S_df, tags = HierarchicalData.load('./data', group_name)
Y_df['ds'] = pd.to_datetime(Y_df['ds'])
Y_df.head()
unique_id ds y
0 total 1998-03-31 84503
1 total 1998-06-30 65312
2 total 1998-09-30 72753
3 total 1998-12-31 70880
4 total 1999-03-31 86893
S_df.iloc[:5, :5]
nsw-hol-city nsw-hol-noncity vic-hol-city vic-hol-noncity qld-hol-city
total 1.0 1.0 1.0 1.0 1.0
hol 1.0 1.0 1.0 1.0 1.0
vfr 0.0 0.0 0.0 0.0 0.0
bus 0.0 0.0 0.0 0.0 0.0
oth 0.0 0.0 0.0 0.0 0.0
tags
{'Country': array(['total'], dtype=object),
 'Country/Purpose': array(['hol', 'vfr', 'bus', 'oth'], dtype=object),
 'Country/Purpose/State': array(['nsw-hol', 'vic-hol', 'qld-hol', 'sa-hol', 'wa-hol', 'tas-hol',
        'nt-hol', 'nsw-vfr', 'vic-vfr', 'qld-vfr', 'sa-vfr', 'wa-vfr',
        'tas-vfr', 'nt-vfr', 'nsw-bus', 'vic-bus', 'qld-bus', 'sa-bus',
        'wa-bus', 'tas-bus', 'nt-bus', 'nsw-oth', 'vic-oth', 'qld-oth',
        'sa-oth', 'wa-oth', 'tas-oth', 'nt-oth'], dtype=object),
 'Country/Purpose/State/CityNonCity': array(['nsw-hol-city', 'nsw-hol-noncity', 'vic-hol-city',
        'vic-hol-noncity', 'qld-hol-city', 'qld-hol-noncity',
        'sa-hol-city', 'sa-hol-noncity', 'wa-hol-city', 'wa-hol-noncity',
        'tas-hol-city', 'tas-hol-noncity', 'nt-hol-city', 'nt-hol-noncity',
        'nsw-vfr-city', 'nsw-vfr-noncity', 'vic-vfr-city',
        'vic-vfr-noncity', 'qld-vfr-city', 'qld-vfr-noncity',
        'sa-vfr-city', 'sa-vfr-noncity', 'wa-vfr-city', 'wa-vfr-noncity',
        'tas-vfr-city', 'tas-vfr-noncity', 'nt-vfr-city', 'nt-vfr-noncity',
        'nsw-bus-city', 'nsw-bus-noncity', 'vic-bus-city',
        'vic-bus-noncity', 'qld-bus-city', 'qld-bus-noncity',
        'sa-bus-city', 'sa-bus-noncity', 'wa-bus-city', 'wa-bus-noncity',
        'tas-bus-city', 'tas-bus-noncity', 'nt-bus-city', 'nt-bus-noncity',
        'nsw-oth-city', 'nsw-oth-noncity', 'vic-oth-city',
        'vic-oth-noncity', 'qld-oth-city', 'qld-oth-noncity',
        'sa-oth-city', 'sa-oth-noncity', 'wa-oth-city', 'wa-oth-noncity',
        'tas-oth-city', 'tas-oth-noncity', 'nt-oth-city', 'nt-oth-noncity'],
       dtype=object)}

我们将数据框分为训练/测试集。

Y_test_df = Y_df.groupby('unique_id').tail(group.horizon)
Y_train_df = Y_df.drop(Y_test_df.index)

3. 基础预测

以下单元格使用 auto_arimanaive 模型计算每个时间序列的 基础预测。请注意,Y_hat_df 包含预测结果,但它们并不一致。

from statsforecast.core import StatsForecast
from statsforecast.models import AutoARIMA, Naive
fcst = StatsForecast(
    df=Y_train_df, 
    models=[AutoARIMA(season_length=group.seasonality), Naive()], 
    freq=group.freq, 
    n_jobs=-1
)
Y_hat_df = fcst.forecast(h=group.horizon)

4. 层次化协调

以下单元使用 HierarchicalReconciliation 类使先前的预测一致。用于使预测一致的方法有:

  • BottomUp: 该方法的一致性通过对上层进行简单的加法来实现。
  • TopDown: 第二种方法将基础层的预测约束到最上层的汇总序列,然后通过使用比例将其分配到分解序列中。
  • MiddleOut: 将基础预测锚定在中间层。
from hierarchicalforecast.core import HierarchicalReconciliation
from hierarchicalforecast.methods import BottomUp, TopDown, MiddleOut
reconcilers = [
    BottomUp(),
    TopDown(method='forecast_proportions'),
    MiddleOut(middle_level='Country/Purpose/State', 
              top_down_method='forecast_proportions')
]
hrec = HierarchicalReconciliation(reconcilers=reconcilers)
Y_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_train_df, S=S_df, tags=tags)

5. 评估

HierarchicalForecast 包含 HierarchicalEvaluation 类,用于评估不同的层级,并且能够计算与基准模型相比的比例指标。

from hierarchicalforecast.evaluation import HierarchicalEvaluation
def mse(y, y_hat):
    return np.mean((y-y_hat)**2)

evaluator = HierarchicalEvaluation(evaluators=[mse])
evaluation = evaluator.evaluate(
        Y_hat_df=Y_rec_df, Y_test_df=Y_test_df.set_index('unique_id'),
        tags=tags, benchmark='Naive'
)
evaluation.filter(like='ARIMA', axis=1).T
level Overall Country Country/Purpose Country/Purpose/State Country/Purpose/State/CityNonCity
metric mse-scaled mse-scaled mse-scaled mse-scaled mse-scaled
AutoARIMA 0.168957 0.132836 0.193802 0.182351 0.199594
AutoARIMA/BottomUp 0.100188 0.08518 0.077097 0.155771 0.199594
AutoARIMA/TopDown_method-forecast_proportions 0.144239 0.132836 0.11976 0.204426 0.227395
AutoARIMA/MiddleOut_middle_level-Country/Purpose/State_top_down_method-forecast_proportions 0.134219 0.145776 0.091276 0.182351 0.215141

参考文献

If you find the code useful, please ⭐ us on Github