1. Prophetの簡単な説明
2. Prophetモデルの構築
3. Prophetパラメータ調整

 


1. Prophetの簡単な説明

ProphetはFacebookで作成された時系列予測packageある。利点は、簡単、直感的、それなりに性能が良い点である!
ARIMAのようにデータの正常性を確保する必要もなく、パラメータが直感的でチューニングが便利である。

また、自動的に変更点を見つけてfittingをするので、周期が変動しているデータに対しても予測が可能である。

(公式ホームページ)


アルゴリズムと使用法のほとんどの説明は、こちらのブログで確認することができる。簡単には、傾向(trend)、季節性(seasonality)、特定のイベント(holiday)を基準にして未来を予測をするアルゴリズムである。しかし、固定された傾向ではなく、確率的に変更点を見つけ傾向を調整することにより、非線形的なデータの説明も可能となる。
 
2. Prophetモデルの構築

Prophetを使用するためにはfbprophetパッケージをインストールする必要がある。以下のコマンドでインストールする。

 

pip install fbprophet


必要なパッケージを読み込む。

import pandas as pd 
import matplotlib.pyplot as plt 
from fbprophet import Prophet


Prophet()のコマンドで新しいモデルオブジェクト化する。例として、金相場の分析をするためARIMA時と同じ金の相場データを準備する。

m = Prophet()

plt.plot(gold_price_series)
plt.show()

 

 

 

このデータをモデルに入れてfittingだけで良い。注意すべき点は、データのcolumns名前を時間はds、値はyと指定する必要があることでだ。

prophet_series = pd.DataFrame(list(zip(gold_price_series.index, gold_price_series['price(USD)'])),columns=['ds', 'y'])
m.fit(prophet_series)


結果を確認して見よう。

forecast = m.predict(prophet_series)
fig, ax = plt.subplots(figsize=(16,5))
m.plot(forecast, ax=ax)
plt.show()


黒い点は実測値、水色の線は予測値、淡い水色の領域は、信頼区間(デフォルトは80%)を示す。凡例がなく、同じグラフを再描画た。

fig, ax = plt.subplots(figsize=(16,5))

plt.plot(forecast['ds'].dt.to_pydatetime(),forecast['yhat'], label='forecast', color='blue')
plt.plot(prophet_series['ds'].dt.to_pydatetime(),prophet_series['y'], label='observations ', color='black')
plt.fill_between(forecast['ds'].dt.to_pydatetime(), forecast['yhat_upper'],forecast['yhat_lower'],color='skyblue',label='80% confidence interval')
plt.legend()
plt.xlabel('date')
plt.ylabel('price(USD)')
plt.show()


plot_componentsの傾向、季節性を確認することができる。

m.plot_components(forecast,figsize=(16,10))
plt.show()


2021年までの金の相場を予測してみよう。まず、下記のコードで将来のデータを作成する。表の一番下を見ると、preiodsで指定されたように、1年後の2021年3月30日までの日付のデータが生じたことを知ることができる。 future = m.make_future_dataframe(periods=365) 既存のデータでfittingしたモデルに将来のデータ(future)を入れてみましょう。

forecast = m.predict(future)
fig, ax = plt.subplots(figsize=(16,5))

plt.plot(forecast['ds'].dt.to_pydatetime(),forecast['yhat'], label='forecast', color='blue')
plt.plot(prophet_series['ds'].dt.to_pydatetime(),prophet_series['y'], label='observations ', color='black')
plt.fill_between(forecast['ds'].dt.to_pydatetime(), forecast['yhat_upper'],forecast['yhat_lower'],color='skyblue',label='80% confidence interval')
plt.legend()
plt.xlabel('date')
plt.ylabel('price(USD)')
plt.show()


2021年のデータの予測値が出てくることを確認することができる。予測結果表の見方は、yhatが予測値、yhat_upperとyhat_lowerが信頼区間である。 print(forecast) 3. Prophetパラメータ調整 Prophetで調整が可能なパラメータは、大きく5つに分けることができる。     ・データの上限下限の設定     ・変動ポイントの設定     ・季節性の調整     ・特別なイベントの追加     ・信頼区間の調整     ・データの上限下限の設定  Prophetで時系列データがある程度以上は大きくならない、あるいは小さくならないを設定することができる。たとえば、世界中の人口に基づいて考えたとき、年間自動車販売台数は1億台以上は大きくならないことが明確な場合は、データを上限を1億と定めることができる。     データの上下限を設定する方法は、まず、モデルのgrowthパラメータをlogisticに設定し、データテーブルに[ 'cap']、下限値は、[ 'floor']という名前の列を作成し、設定すればよい。するのコードは、上限は2000、下限は250に設定した。(上限と下限を両方設定する必要はなく、一方だけ設定しても良い。)

m = Prophet(growth = 'logistic')
prophet_series = pd.DataFrame(list(zip(gold_price_series.index, gold_price_series['price(USD)'])),columns=['ds', 'y'])
prophet_series['cap'] = 2000
prophet_series['floor'] = 250
m.fit(prophet_series)
forecast = m.predict(prophet_series)
fig, ax = plt.subplots(figsize=(16,5))
m.plot(forecast, ax=ax)
plt.show()


グラフを見ると、グラフの上下に黒い点線ができたことがわかる、この点線が設定した上限と下限の線になる。予測は、いつもこの点線の内側で行われる。上記の例は、上下限を一定値にしたが、必ずしも一定の値を入れる必要はない。例えば、市場の全体のサイズが一定の成長率で成長すれば、時間に応じた上限値を調整することも可能である。下記のコードは上下限値の設定が変動を加えた例示である。

m = Prophet(growth = 'logistic')
prophet_series = pd.DataFrame(list(zip(gold_price_series.index, gold_price_series['price(USD)'])),columns=['ds', 'y'])
prophet_series['cap'] = prophet_series['y'] * 1.1
prophet_series['floor'] = prophet_series['y'] * 0.9
m.fit(prophet_series)
forecast = m.predict(prophet_series)
fig, ax = plt.subplots(figsize=(16,5))
m.plot(forecast, ax=ax)
plt.show()


 ・変動ポイントの設定  上述のようにProphetは、自動的にトレンドの変動ポイントを見つける。統計的に適切であると考えている区間に分け、各区間ごとにfittingを新たにする方式である。私たちは、これらの変動のポイントの数、探し基準となるデータの長さは、どの程度の変化があるときに変動点にするか(flexibility)などを調整して、モデルをチューニングすることができる。 まず、モデルが認識した変動ポイントを確認してみよう。

from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)


赤い点線がこのモデルが変動点で取ったポイントである。各区間では、赤い直線が直線で接続されていることがわかる。これらの線形直線に季節性、休日、残差などを入れたのがモデルの予測値となる。prophetはoverfittingを避けるために、デフォールトで全データの80%を使用して変動点を見つける。この変動ポイントを探すために用いるデータの数(範囲)は、モデルのハイパーパラメータであるchangepoint_rangeを変える調整が可能である。下記のコードは、前の50%のみを使用する場合の例である。

m = Prophet(changepoint_range=0.5)
m.fit(prophet_series)
forecast = m.predict(prophet_series)

fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)


また、変動点を見つける流動性flexibility)を調節するためには、changepoint_prior_scaleのハイパーパラメータが用いられる。この値を上げると、より柔軟で探す( - >データのオーバーフィッティング恐れがある)

m = Prophet(changepoint_prior_scale=0.5)
m.fit(prophet_series)
forecast = m.predict(prophet_series)

fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)


逆に、この値を小さくすると、変動点を見つける流動性を下げることもできる。( - >アンダーフィッティングに注意)

m = Prophet(changepoint_prior_scale=0.001)
m.fit(prophet_series)
forecast = m.predict(prophet_series)

fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)


これらの変動点は、指定したchangepoint_prior_scaleに応じて自動的にその数が決まる。これらの数字を指定したい場合 n_changepointsパラメータの数を変更すればいい。また、changepointsで特定の日付を変動点として指定することも可能である。  ・季節性の調整 上記の変動点調整は、トレンドの変動点を設定するパラメータであるのに対して、下記のパラメータは、季節性を調整するパラメータである。 yearly_seasonality、weekly_seasonality、daily_seasonality 季節性の推定は、フーリエ級数の小計を利用するが、いくつの次数までの和を利用するかを定めるパラメータである。この値を上げると季節性のfittingがより複雑になる。下の上のグラフはyearly_seasonalityが10である場合(default)であり、下の下のグラフは、20に上げた場合である。 seasonality_mode 季節性の分散が時間に応じて変動する場合seasonality_modeをmultiplicativeに設定する必要があります。 上のグラフは、seasonality_modeをadditive(defualt)である場合で、1950年付近は、季節性を過度に推定し、1960年代には実データより少なく推定することがわかる。一方、下のグラフは、seasonality_modeをmultiplicativeに変更したものであり、もっとデータを説明できるモデルになったことが確認できる。 seasonality_prior_scale 全体のデータからの季節性の影響度を調整するパラメータで値を下げる、季節性の影響度を下げることができる。(default10)   add_seasonality パラメータというよりは、新しいカスタマイズした季節性を追加するメソッドである。

m = Prophet(weekly_seasonality=False)
m.add_seasonality(name='monthly', period=30.5, fourier_order=5)
forecast = m.fit(df).predict(future)
fig = m.plot_components(forecast)


 ・特別なイベントの追加 下記のコードのようにholidaysに特別な日付のイベント、休日などを入れることが可能である。

playoffs = pd.DataFrame({
  'holiday': 'playoff',
  'ds': pd.to_datetime(['2008-01-13', '2009-01-03', '2010-01-16',
                        '2010-01-24', '2010-02-07', '2011-01-08',
                        '2013-01-12', '2014-01-12', '2014-01-19',
                        '2014-02-02', '2015-01-11', '2016-01-17',
                        '2016-01-24', '2016-02-07']),
  'lower_window': 0,
  'upper_window': 1,
})
superbowls = pd.DataFrame({
  'holiday': 'superbowl',
  'ds': pd.to_datetime(['2010-02-07', '2014-02-02', '2016-02-07']),
  'lower_window': 0,
  'upper_window': 1,
})
holidays = pd.concat((playoffs, superbowls))
m = Prophet(holidays=holidays)
forecast = m.fit(df).predict(future)


そのほかseasonality_prior_scaleのようholidays_prior_scaleでholidaysの強度調節が可能で、下記のように追加の説明変数を入れlinear regression項目を追加することができる。

def nfl_sunday(ds):
    date = pd.to_datetime(ds)
    if date.weekday() == 6 and (date.month > 8 or date.month < 2):
        return 1
    else:
        return 0
df['nfl_sunday'] = df['ds'].apply(nfl_sunday)

m = Prophet()
m.add_regressor('nfl_sunday')
m.fit(df)

future['nfl_sunday'] = future['ds'].apply(nfl_sunday)

forecast = m.predict(future)
fig = m.plot_components(forecast)


add_regressorの強度は、上記のholidays_prior_scaleのに連動される。 holidaysとadd_regressorは似て見えるが、add_regressorは1、0のようにbinaryである必要がなく、連続数字を入れることが可能である。  ・信頼区間の調整 信頼区間は、調整はinterval_widthとすることができる。95%信頼区間に変更したコードである。

forecast = Prophet(interval_width=0.95).fit(df).predict(future)


季節性の信頼区間を求めたい場合は、mcmc_sampleを指定しなければならない。指定する数値は、季節性の信頼区間を求めるために、いくつのサンプルを使用するかをを定めるものである。

m = Prophet(mcmc_samples=300)
forecast = m.fit(df).predict(future)
fig = m.plot_components(forecast)
plt.show()