【GluonTS】【PyTorch】「feat_dynamic_real」を使ってみる

はじめに

前回PyTorchでGluonTSのDeepARモデルが使用できることを紹介しました。
touch-sp.hatenablog.com
今回は同じモデルで「feat_dynamic_real」を使ってみようと思います。

「feat_dynamic_real」とは?

時系列予測をする時に求めたい値はターゲット変数と言います。そのターゲット変数に影響を及ぼす変数を説明変数と言います。

その説明変数のうち将来まで値がわかっているものをGluonTSでは「feat_dynamic_real」と言っています。

これだけでは何のことかわからないと思いますので具体例で説明します。

今回使用させて頂くデータはUCI Machine Learning Repositoryの「Bike Sharing Dateset」です。
archive.ics.uci.edu
レンタル自転車の貸し出し数のデータになります。


自転車の貸し出し数をターゲット変数とした時にそれに影響を及ぼす説明変数はどんなものがあるか?
例えば季節、曜日、天気、気温などです。ざっくり言うとそれが「feat_dynamic_real」です。


天気、気温などは将来の値がわからないので本来であれば「feat_dynamic_real」としては扱えません。しかし今回は天気予報の精度が100%として、すべて「feat_dynamic_real」として扱いました。


「feat_dynamic_real」についてなんとなく理解できたでしょうか?


使用するには注意点があります。曜日、天気などはカテゴリーデータなので「feat_dynamic_real」として扱う場合にはOne-Hotベクトル化する必要があります。
One-Hotベクトル化はPandasのget_dummiesを使えば簡単です。
touch-sp.hatenablog.com

Pythonスクリプト

import warnings
warnings.simplefilter('ignore')

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

from gluonts.dataset.common import ListDataset
from gluonts.torch.model.deepar import DeepAREstimator
from gluonts.evaluation.backtest import make_evaluation_predictions
from gluonts.dataset.util import to_pandas

from autogluon.core.utils.loaders import load_zip
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00275/Bike-Sharing-Dataset.zip'
load_zip.unzip(url, unzip_dir = '.')

df = pd.read_csv('day.csv',index_col=1)

feat1 = np.array(df.hum).reshape((1,-1))
feat2 = np.array(df.temp).reshape((1,-1))
feat3 = np.array(df.windspeed).reshape((1,-1))

feat4 = np.array(pd.get_dummies(df.weekday)).transpose((1,0))
feat5 = np.array(df.workingday).reshape((1,-1))
feat6 = np.array(pd.get_dummies(df.weathersit)).transpose((1,0))
feat7 = np.array(pd.get_dummies(df.season)).transpose((1,0))

features_real = np.concatenate([feat1, feat2, feat3, feat4, feat5, feat6, feat7], axis=0)

training_data = ListDataset(
    [{"start": df.index[0], 
        "target": df.cnt[:-14],
        "feat_dynamic_real": features_real[:,:-14],
        }],
    freq = "1D")

test_data = ListDataset(
    [{"start": df.index[0], 
        "target": df.cnt,
        'feat_dynamic_real': features_real,
        }],
    freq = "1D")

estimator = DeepAREstimator(
    freq='1D',
    prediction_length=14,
    context_length=28,
    num_feat_dynamic_real = 18,
    trainer_kwargs=dict(max_epochs=50),
)

predictor = estimator.train(training_data=training_data)

forecast_it, ts_it = make_evaluation_predictions(
    dataset=test_data,      # test dataset
    predictor=predictor,    # predictor
    num_samples=100,        # number of sample paths we want for evaluation
)

plot_length = 50
prediction_intervals = (50.0, 90.0)
legend = ["observations", "median prediction"] + [f"{k}% prediction interval" for k in prediction_intervals][::-1]

for x, y in zip(test_data, forecast_it):
    to_pandas(x)[-plot_length:].plot()
    y.samples = y.samples.clip(min=0)
    y.plot(color='g', prediction_intervals=prediction_intervals)
    plt.grid(which='both')
    plt.legend(legend, loc='upper left')

plt.show()

結果

f:id:touch-sp:20211129155750p:plain:w480

MXNetを使った場合

今回の記事は過去のMXNet用のスクリプトをPyTorch用に書き換えただけです。
MXNet用のスクリプトはこちらを参照して下さい。
touch-sp.hatenablog.com

その他

ZIPファイルのダウンロード、解凍に関してはこちらを参照して下さい。
touch-sp.hatenablog.com