時系列予測システムProphetによる周期性分析

現実の多くの時系列データは周期性を持ちます。
日次データは7日の周期性を持つことが多いでしょう。
毎週日曜日は会社や学校が休みだから家にいるとか、月曜日はプロ野球の試合が無いからゆっくり残業するだとか、人々の行動パターンが曜日によって規定されることがあるからです。

また季節によっても行動は変わります。
毎年年度末には学校に入学したり入社したり異動があったりします。
このため引越し費用は高騰し、賃貸契約も取り引き量が圧倒的に増大します。
この場合、365日(うるう年は366日)の周期性があると考えなければなりません。

ある不動産会社が自社の成約数を日ごとに予測しようとしたとしましょう。
このとき分析者が曜日と季節の両方を考慮しなければ、彼が上司にポンコツ扱いされるのは避けられないと思います。
なぜなら土日と2月3月が多くなるのは当たり前すぎるからです。

当然求められるこの要件ですが、従来の時系列分析手法(代表的なのはARIMA)ではこのような複数の周期性を考慮することは難しかったです。
それは対前期比(もしくは差)という考え方の限界であり、このようなモデルで周期性を捕らえようとしている限り解決困難な問題だと私は思います。
時系列予測システムProphetは前期比という考え方を持たない予測モデルを用いるため週次周期性と年次周期性との両方を捉えることができます。
この点において伝統的な手法に対して圧倒的なアドバンテージがあるのです。

【Prophetの周期性モデル】

ではProphetはどのようにして週次と年次の周期性分析を可能にするのか。
一言で説明しますと、周期性分析はフーリエ分析を基礎としているからです。
Prophetの季節性成分は次のように普通のフーリエ級数で定義されます。


\displaystyle s(t)=\sum_{n=-N}^{N}c_{n}e^{\mathrm{i}\frac{2n\pi t}{P}} \ \ \cdots(1)

式(1)のPが周期、Nがフーリエ分析に用いる波数の上限値です。
Prophetは(P,N)=(7,3),(365.25,10)の二種類の異なるフーリエ係数を足しあわせたものを周期性変動項とします。
もちろん、周期7日の前者が一週間の周期性、周期365.25日の後者が年間の周期性です。

また理論的には周期7,365.25以外の周期性が存在する場合にはその要素を簡単に追加することが可能だと思います。
Prophetが一般化加法モデルに基づいているからです。

(この論理を応用して異なる周期の波を足し合わせることで振幅が振動する周期性モデルができそうなんだけどなー)

追記
prophet v0.2にて任意の周期のフーリエ係数を追加できるようになりました。
これについて一番下に説明を追加しています。

【事前分布】

フーリエ係数の事前分布は平均0, 分散\sigma^2の正規分布に従うとします。
よって\sigmaを変えることでProphet分析における周期性効果の強さを制御することができます。
その設定のためには関数prophetの引数seasonality.prior.scaleを変更してください。
デフォルトでは10になっていますので、周期性効果をさらに強めたい場合は大きく、弱めたい場合は小さくします。

【周期性の選択】

もし
「私は年次の周期性のみの分析をしたい。週次の周期性は考慮したくない」
という場合は関数prophetの引数weekly.seasonalityFALSEに設定すれば実現できます。

ichiro

#R
library(prophet)
ichiro <- read.csv("data/ichiro.csv")
ichiro <- ichiro[y != 0,]
ichiro$y <- log(ichiro$y)
m <- prophet(ichiro, weekly.seasonlity=FALSE)
future <- make_future_dataframe(ichiro, periods=365)
forecast <- predict(m, future)
head(forecast)
#          ds            t    trend yhat_lower yhat_upper trend_lower trend_upper seasonal_lower seasonal_upper     yearly yearly_lower  yearly_upper   seasonal     yhat
#1 2008-02-01 0.0000000000 8.062675   7.374262   8.412155    8.062675    8.062675     -0.1607014     -0.1607014 -0.1607014   -0.1607014   -0.1607014 -0.1607014 7.901974
#2 2008-02-02 0.0003436426 8.064006   7.345606   8.395586    8.064006    8.064006     -0.1763822     -0.1763822 -0.1763822   -0.1763822   -0.1763822 -0.1763822 7.887624
#3 2008-02-03 0.0006872852 8.065338   7.363881   8.394797    8.065338    8.065338     -0.1902982     -0.1902982 -0.1902982   -0.1902982   -0.1902982 -0.1902982 7.875039
#4 2008-02-04 0.0010309278 8.066669   7.324733   8.394096    8.066669    8.066669     -0.2021159     -0.2021159 -0.2021159   -0.2021159   -0.2021159 -0.2021159 7.864553
#5 2008-02-05 0.0013745704 8.068000   7.323117   8.373892    8.068000    8.068000     -0.2115694     -0.2115694 -0.2115694   -0.2115694   -0.2115694 -0.2115694 7.856431
#6 2008-02-06 0.0017182131 8.069331   7.271740   8.393421    8.069331    8.069331     -0.2184671     -0.2184671 -0.2184671   -0.2184671   -0.2184671 -0.2184671 7.850864

確かにweeklyの項目が見当たらず、週次の周期性分析は行っていないようです。
年次周期性についてもyearly.seasonality=FALSEとすれば同様に設定できます。

【さらに高度な周期性分析(追記)】

prophetv0.1ではyearlyとweeklyの周期性しか使えませんでしたが、prophet v0.2で任意の周期のモデルを設定することができるようになりました。
またFourier係数の最大波数も自由に設定できるようになっています。

周期項の設定は関数add_seasonalityを使います。
これを使うときはprophetモデルを作る手順が若干変わるので気をつけてください。
従来は予測したいデータフレームに関数prophetを作用させることでprophetモデルを作成しました。
しかし周期項を設計する場合には先にprophetのモデル変数を作って周期性の設計をしてから、モデルに関数fit.prophetを作用させることで最終的なモデル変数を作成します。

#R
m <- prophet()
m <- add_seasonality(m, name = "monthly", period = 30.5, fourier.order = 5)
m <- fit.prophet(m, ichiro)
future <- make_future_dataframe(m, periods = 365)
fcst <- predict(m, future)
prophetの予測にmonthly seasonalityを追加

参考サイト

関連記事

コメントを残す