生成特征

利用StatsForecast模型创建特征

一些模型会创建序列的内部表示,这些表示可以为其他模型提供有用的输入。一个例子是 MSTL 模型,它将序列分解为趋势和季节性分量。本指南将向您展示如何使用 mstl_decomposition 函数来提取这些特征以进行训练,然后使用它们的未来值进行推断。

import os
from functools import partial

import pandas as pd
import statsforecast
from statsforecast import StatsForecast
from statsforecast.feature_engineering import mstl_decomposition
from statsforecast.models import ARIMA, MSTL
from utilsforecast.evaluation import evaluate
from utilsforecast.losses import smape, mase
# 这样,预测方法的输出结果中就会包含一个id列。 
# 而不是作为索引
os.environ['NIXTLA_ID_AS_COL'] = '1'
df = pd.read_parquet('https://datasets-nixtla.s3.amazonaws.com/m4-hourly.parquet')
uids = df['unique_id'].unique()[:10]
df = df[df['unique_id'].isin(uids)]
df.head()
unique_id ds y
0 H1 1 605.0
1 H1 2 586.0
2 H1 3 586.0
3 H1 4 559.0
4 H1 5 511.0

假设您想使用ARIMA模型来预测您的序列,但您想将MSTL模型中的趋势和季节性成分作为外部回归量来纳入。您可以定义要使用的MSTL模型,然后将其提供给mstl_decomposition函数。

freq = 1
season_length = 24
horizon = 2 * season_length
valid = df.groupby('unique_id').tail(horizon)
train = df.drop(valid.index)
model = MSTL(season_length=24)
transformed_df, X_df = mstl_decomposition(train, model=model, freq=freq, h=horizon)

这生成了我们应该用于训练的DataFrame(添加了趋势和季节性列),以及我们应该用于预测的DataFrame。

transformed_df.head()
unique_id ds y trend seasonal
0 H1 1 605.0 501.350550 124.683643
1 H1 2 586.0 506.424549 87.115039
2 H1 3 586.0 511.453736 79.479564
3 H1 4 559.0 516.434474 45.616992
4 H1 5 511.0 521.362991 -10.940498
X_df.head()
unique_id ds trend seasonal
0 H1 701 626.519191 -22.738998
1 H1 702 627.423191 -108.992314
2 H1 703 628.146391 -148.675478
3 H1 704 628.724951 -183.715284
4 H1 705 629.187799 -208.038694

我们现在可以训练我们的ARIMA模型并计算我们的预测。

sf = StatsForecast(
    models=[ARIMA(order=(1, 0, 1), season_length=season_length)],
    freq=freq
)
preds = sf.forecast(h=horizon, df=transformed_df, X_df=X_df)
preds.head()
unique_id ds ARIMA
0 H1 701 597.716125
1 H1 702 513.244507
2 H1 703 475.042450
3 H1 704 441.217743
4 H1 705 417.895813

我们现在可以评估性能。

def compute_evaluation(preds):
    full = preds.merge(valid, on=['unique_id', 'ds'])
    mase24 = partial(mase, seasonality=24)
    res = evaluate(full, metrics=[smape, mase24], train_df=train).groupby('metric')['ARIMA'].mean()
    res_smape = '{:.1%}'.format(res['smape'])
    res_mase = '{:.1f}'.format(res['mase'])
    return pd.Series({'mase': res_mase, 'smape': res_smape})
compute_evaluation(preds)
mase      1.0
smape    3.7%
dtype: object

并将其与仅使用序列值进行比较。

preds_noexog = sf.forecast(h=horizon, df=train)
compute_evaluation(preds_noexog)
mase      2.3
smape    7.7%
dtype: object

Give us a ⭐ on Github