NeuralProphetを使ってみた

* 製造業出身のデータサイエンティストがお送りする記事
* 今回は時系列解析手法のNeuralProphetを使ってみました

##はじめに
過去に時系列解析に関しては何個か整理しておりますので、興味ある方は参照して頂けますと幸いです。

* [時系列解析](https://qiita.com/DS27/items/1e998a58488e76bfcbdc)
* [状態空間モデル](https://qiita.com/DS27/items/cd0e11c2b9eb097c606b)
* [時系列予測をGBDTで実装してみた](https://qiita.com/DS27/items/85abd5862367ff6eaadb)
* [時系列解析手法のSARIMAモデルを試してみた](https://qiita.com/DS27/items/b70aad44721dfa7ac5f7)
* [ProphetをOptunaでハイパラチューニングをしてみた](https://qiita.com/DS27/items/d539e797f533ebc87419)

##NeuralProphetとは
NeuralProphetとは、Facebookが公開しているProphetにDeep Learningの技術を組合せており、2017年にリリースされた時系列解析ライブラリです。Prophet同様に使いやすいです。

## NeuralProphetの実装
今回も使用したデータは、月ごとの飛行機の乗客数データです。

最初にライブラリーをインストールしますが、pipで簡単にインストール可能です。

```php
pip install neuralprophet
```

ここから、普通にライブラリーをインポートして行きます。

```php
# ライブラリーのインポート
import pandas as pd
import numpy as np
import seaborn as sns
from matplotlib import pylab as plt

%matplotlib inline

# NeuralProphet
from neuralprophet import NeuralProphet

# 評価指標
from sklearn.metrics import mean_absolute_error

import warnings

warnings.filterwarnings("ignore")

# https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/AirPassengers.html
df = pd.read_csv("../../data/AirPassengers.csv")

# float型に変換
df["#Passengers"] = df["#Passengers"].astype("float64")
df = df.rename(columns={"#Passengers": "Passengers"})

# datetime型に変換にする
df.Month = pd.to_datetime(df.Month)

# データの中身を確認
df.head()
```
![スクリーンショット 2020-12-05 12.41.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/e5bf2b87-d8c3-49ef-66a9-7e697e6c9b7f.png)

```php
fig, ax = plt.subplots()
a = sns.lineplot(x="Month", y="Passengers", data=df)
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/a9348171-8ca1-1915-1590-d840da3ba4e0.png)

次に学習データとテストデータに分割します。

```php
df = df.rename(columns={"Month": "ds", "Passengers": "y"})
df = df[["ds", "y"]]

# 学習データとテストデータの分割
test_length = 12
df_train = df.iloc[:-test_length]
df_test = df.iloc[-test_length:]
```

各種パラメータを下記のように設定できます。

```php
params = {
    "growth": "linear",
    "changepoints": None,
    "n_changepoints": 10,
    "changepoints_range": 0.9,
    "trend_reg": 0,
    "trend_reg_threshold": False,
    "yearly_seasonality": True,
    "weekly_seasonality": False,
    "daily_seasonality": False,
    "seasonality_mode": "multiplicative",
    "seasonality_reg": 0,
    "n_forecasts": 1,
    "n_lags": 0,
    "num_hidden_layers": 0,
    "d_hidden": None,
    "ar_sparsity": None,
    "learning_rate": None,
    "epochs": 1000,
    "batch_size": None,
    "loss_func": "Huber",
    "train_speed": None,
    "normalize": "auto",
    "impute_missing": True,
}
```

モデルを構築します。

```php
model = NeuralProphet(**params)
model.fit(df_train,
          validate_each_epoch=True,
          valid_p=0.2,
          freq='M',
          plot_live_loss=True)
```

各種パラメータの意味合いは下記の通りです。

- validate_each_epoch：各エポックの検証データでモデルのパフォーマンスを検証するかどうか
- valid_p：検証に使用する必要があるデータの割合
- plot_live_loss：モデルのトレーニングと検証の損失のライブプロットを生成するかどうか

![スクリーンショット 2021-08-12 10.37.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/037177f8-3dfb-bee6-d6ff-fa4dc4b15e5f.jpeg)

次に予測モデルの精度検証用データを生成します。

```php
# NeuralProphet 予測モデルの精度検証用データの生成
future = model.make_future_dataframe(
    df_train, periods=test_length, n_historic_predictions=len(df_train)
)
pred = model.predict(future)
```

予測結果は下記のように可視化できます。

```php
# NeuralProphet 予測モデルの予測結果（学習データ期間＋テストデータ期間）
pred_plot = model.plot(pred)  # 予想値（点は学習データの実測値）
component_plot = model.plot_components(pred)  # モデルの要素分解
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/247b9923-abfd-f9fc-5002-4445d0f4f8db.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/7d181ca7-5d81-cdd9-6d87-63dfa97647b1.png)

最後に評価指標を算出します。

```php
# テストデータに予測値を結合
df_test["NeuralProphet Predict"] = pred.iloc[-test_length:].loc[:, "yhat1"]

# NeuralProphet 予測モデルの精度検証（テストデータ期間）
print("MAE(NeuralProphet):")
print(mean_absolute_error(df_test["y"], df_test["NeuralProphet Predict"]))

#MAE(NeuralProphet):
#16.130884806315105
```

##さいごに
最後まで読んで頂き、ありがとうございました。
今回は時系列解析手法のNeuralProphetを使ってみました。

訂正要望がありましたら、ご連絡頂けますと幸いです。