ProphetをPythonで使いたい(1:基本編)

Prophetは時系列モデルを簡単に扱える手法です。 Facebookから発表され、Pythonからも使用することができます。

モデリングでいじれる部分がかなり多いので、何本かの記事に分けて試していきます。

使い方

sklearn-likeな呼び出しになっています。
predict前の準備のみ注意が必要です。

from fbprophet import Prophet

mdl = Prophet()
#データをfit
mdl.fit(mdl_df)

#predict
future = mdl.make_future_dataframe(periods=0,freq='D')
pred  = mdl.predict(future)

使ってみる

テストデータをつくる

テストデータをつくって試してみます。 今回は

  • 祝日
  • 曜日周期
  • 外部効果でベースがあがる
  • よくわからないトレンド
  • 別の変量効果

といろいろな要素を盛り込んでみます。

import math
import random
import pandas as pd
import jpholiday

N  = 365

#祝日効果
dt = pd.Series(pd.date_range(start='2019-01-01',periods=N))
f = lambda x : random.random() * 5 if jpholiday.is_holiday_name(x) else 0
hol = dt.apply(f)

#外部効果で突然上がる効果
trend1 = [ 2/(1 + math.exp(-1*(i - N/2) * 0.1)) for i in  range(N)]

#変な周期性効果
trend2 = [ math.cos(i * 0.25) for i in range(N)]

#曜日効果
season_base = [ random.random() for i in range(7)]
season = [season_base[i%7] for i in range(N)]

#別の変数
x = pd.Series([random.random() * 0.01 for i  in range(N)]).cumsum()
y = x.apply(lambda x : x * 1.25 + random.gauss(mu=0.5,sigma=0.25))

#ノイズ
noise = [random.random() for i in range(N)]

df = pd.DataFrame(
    {
        "trend1":trend1,
        "trend2":trend2,
        "season":season,
        "noise":noise,
        "hol":hol,
        "y":y
    }
)


#上記の要素を足し合わせる

ts = df.apply(lambda x : sum(x),axis=1)
ts.plot()

f:id:esu-ko:20200911195603p:plain

データの読み込みとモデリング

ほとんどいじらずにフィッティングしてみます。

つっこむデータはdsyというカラム名で入れる必要があります。

mdl_df = pd.DataFrame(
    {
        "ds":pd.date_range(start='2019-01-01',periods=365),
        'y':ts
        
    }
    
)

フィッティングしていきます。 一年分のデータかつ,時間情報はないので、weekly以外の季節性をオフにしています。(勝手にオフにはしてくれるのですが、わかりやすくするため)

from fbprophet import Prophet

mdl = Prophet(
    yearly_seasonality=False,
    weekly_seasonality=True,
    daily_seasonality=False
)
mdl.fit(
    mdl_df
)
future = mdl.make_future_dataframe(periods=0,freq='D')
pred  = mdl.predict(future)
pred.head()
pred.yhat.plot()
ts.plot()

なんとなくこれでも、緩やかな形はとらえてくれてはいます。実務上、とてもざっくりみるだけならこれでもよいこともあるかもしれません。 f:id:esu-ko:20200911200037p:plain

ただし、外部効果としていれてロジスティックの形などはほとんどとれていません。時系列の分析としては、まだまだ仮定を入れていく必要がありそうです。 f:id:esu-ko:20200911201317p:plain

予測してみる

periodsの期間を長くとるだけです。

future = mdl.make_future_dataframe(periods=365,freq='D')
pred  = mdl.predict(future)
pred.yhat.plot()
ts.plot()

f:id:esu-ko:20200911200212p:plain