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
生成特征
利用StatsForecast模型创建特征
一些模型会创建序列的内部表示,这些表示可以为其他模型提供有用的输入。一个例子是 MSTL
模型,它将序列分解为趋势和季节性分量。本指南将向您展示如何使用 mstl_decomposition
函数来提取这些特征以进行训练,然后使用它们的未来值进行推断。
# 这样,预测方法的输出结果中就会包含一个id列。
# 而不是作为索引
'NIXTLA_ID_AS_COL'] = '1' os.environ[
= pd.read_parquet('https://datasets-nixtla.s3.amazonaws.com/m4-hourly.parquet')
df = df['unique_id'].unique()[:10]
uids = df[df['unique_id'].isin(uids)]
df 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函数。
= 1
freq = 24
season_length = 2 * season_length
horizon = df.groupby('unique_id').tail(horizon)
valid = df.drop(valid.index)
train = MSTL(season_length=24)
model = mstl_decomposition(train, model=model, freq=freq, h=horizon) transformed_df, X_df
这生成了我们应该用于训练的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模型并计算我们的预测。
= StatsForecast(
sf =[ARIMA(order=(1, 0, 1), season_length=season_length)],
models=freq
freq
)= sf.forecast(h=horizon, df=transformed_df, X_df=X_df)
preds 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):
= preds.merge(valid, on=['unique_id', 'ds'])
full = partial(mase, seasonality=24)
mase24 = evaluate(full, metrics=[smape, mase24], train_df=train).groupby('metric')['ARIMA'].mean()
res = '{:.1%}'.format(res['smape'])
res_smape = '{:.1f}'.format(res['mase'])
res_mase return pd.Series({'mase': res_mase, 'smape': res_smape})
compute_evaluation(preds)
mase 1.0
smape 3.7%
dtype: object
并将其与仅使用序列值进行比较。
= sf.forecast(h=horizon, df=train)
preds_noexog compute_evaluation(preds_noexog)
mase 2.3
smape 7.7%
dtype: object
Give us a ⭐ on Github