ProphetをOptunaでハイパラチューニングをしてみた


  • 製造業出身のデータサイエンティストがお送りする記事
  • 今回は時系列解析手法のProphetをOptunaでハイパラチューニングをしてみました

はじめに

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

Prophetとは

Prophet は Facebook が公開しているオープンソースの時系列解析ライブラリです。

Prophetのメリットは大きく下記があります。

1.モデル式設計の柔軟性が高い
2.サンプル間隔の柔軟性が高い
3.高速に計算可能
4.パラメータが理解しやすい

詳細はProphetの公式ドキュメントを参照してください。

Prophet実装

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


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

from fbprophet import Prophet
from fbprophet.plot import add_changepoints_to_plot

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()

# データの可視化
fig, ax = plt.subplots()
a = sns.lineplot(x="Month", y="Passengers", data=df)
plt.show()

Prophetでモデルを構築します。

def objective_variable(train, valid):

    def objective(trial):
            params = {
                    'changepoint_range' : trial.suggest_discrete_uniform('changepoint_range', 0.8, 0.95, 0.001),
                    'n_changepoints' : trial.suggest_int('n_changepoints', 20, 35),
                    'changepoint_prior_scale' : trial.suggest_discrete_uniform('changepoint_prior_scale',0.001, 0.5, 0.001),
                    'seasonality_prior_scale' : trial.suggest_discrete_uniform('seasonality_prior_scale',1, 25, 0.1),
            }

            # fit_model
            model = Prophet(
                changepoint_range = params['changepoint_prior_scale'],
                n_changepoints=params['n_changepoints'],
                changepoint_prior_scale=params['changepoint_prior_scale'],
                seasonality_prior_scale = params['seasonality_prior_scale'],
            )

            model.fit(train)
            future = model.make_future_dataframe(periods=len(valid))

            forecast = model.predict(future)
            valid_forecast = forecast.tail(len(valid))

            val_mape = np.mean(np.abs((valid_forecast.yhat-valid.y)/valid.y))*100

            return val_mape

    return objective

def optuna_parameter(train, valid):
    study = optuna.create_study(sampler=optuna.samplers.RandomSampler(seed=10))
    study.optimize(objective_variable(train, valid), timeout=500)
    optuna_best_params = study.best_params

    return study

df = df.rename(columns={'Month':'ds','Passengers':'y'})
df = df[['ds','y']]
df_train = df[df['ds'] < '1956-04-01']
df_valid = df[(df['ds'] >= '1956-04-01')&(df['ds'] < '1957-04-01')]
df_test = df[df['ds'] >= '1957-04-01']

study = optuna_parameter(df_train, df_valid)

あとは、チューニング結果のハイパーパラメータを使ってモデルの学習と予測を行います。

# fit_model
best_model = Prophet(
    changepoint_range = study.best_params['changepoint_prior_scale'],
    n_changepoints=study.best_params['n_changepoints'],
    seasonality_prior_scale = study.best_params['seasonality_prior_scale'],
    changepoint_prior_scale=study.best_params['changepoint_prior_scale'],
)

best_model.fit(df_train)
feature_test = best_model.make_future_dataframe(periods=len(df_valid)+len(df_test), freq='M')

forecast_test = best_model.predict(feature_test)
forecast_test_plot = best_model.plot(forecast_test)

fig, ax = plt.subplots()
df.y.plot(ax=ax, label='Original', linestyle="dashed")
forecast_test.yhat.plot(ax=ax, label='Predict')
ax.legend()

さいごに

最後まで読んで頂き、ありがとうございました。
今回は時系列解析手法のProphetをOptunaでハイパラチューニングをしてみました。

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