自分で使うにあたって、頭の整理も兼ねて記事にしました。
rubyで時系列予測がしたい!
- 全部rubyでやりたい
- railsで動かしてるシステムの中で予測値を出したい
- pythonやRなどでいいライブラリはいっぱいあるが、railsとのつなぎこみが面倒臭い
- スプレッドシートのTREND関数などもあるけど、やっぱりrailsとのつなぎこみが面倒臭い
- 全部rubyでやりたい
prophetを使おう
prophet-rbというgemを使います。
https://github.com/ankane/prophet
元はfacebook/prophet(https://github.com/facebook/prophet )。これを移植してきたもの。
- 複数の季節性
- 線形/非線形成長
- 祝日など特別な日のハンドリング
- 欠損値処理 などをいい感じにやってくれる。
インストール
Gemfileに以下の行を追記。
gem 'prophet-rb'
まずは試しに
{ 時系列: 実績値 }のハッシュを用意します。
series = {
Date.parse("2020-01-01") => 100,
Date.parse("2020-01-02") => 150,
Date.parse("2020-01-03") => 136,
Date.parse("2020-01-04") => 130,
Date.parse("2020-01-05") => 128,
Date.parse("2020-01-06") => 120,
Date.parse("2020-01-07") => 135,
Date.parse("2020-01-08") => 136,
Date.parse("2020-01-09") => 127,
Date.parse("2020-01-10") => 138
}
Prophet.forecast(series, count: 3) # 二つ目の引数で予測値をいくつ返すか指定
これを実行すると、下のように予測値が得られる、というわけです。予測に使う元データは最低10個必要です。
> Prophet.forecast(series, count: 3)
=> {Sat, 11 Jan 2020=>136.19586588066147, Sun, 12 Jan 2020=>137.322312420595, Mon, 13 Jan 2020=>138.44875896052858}
CSVを読み込んで時系列予測をする
df = Rover.read_csv("example_wp_log_peyton_manning.csv")
df.head
こういうcsvがあったとする。
ds | y |
---|---|
2007-12-10 | 9.59076113 |
2007-12-11 | 8.51959031 |
2007-12-12 | 8.18367658 |
2007-12-13 | 8.07246736 |
2007-12-14 | 7.89357207 |
m = Prophet.new
m.fit(df)
fitメソッドで予測。
将来の時系列を与えて予測してみる
future = m.make_future_dataframe(periods: 365)
future.tail
ds |
---|
2007-12-10 |
2007-12-11 |
2007-12-12 |
2007-12-13 |
2007-12-14 |
forecast = m.predict(future)
forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail
ds | yhat | yhat_lower | yhat_upper |
---|---|---|---|
2017-01-15 | 8.21192840 | 7.52526442 | 8.92389960 |
2017-01-16 | 8.53696359 | 7.79124970 | 9.22620028 |
2017-01-17 | 8.32439891 | 7.62482699 | 9.04719328 |
下限/上限まで出してくれる!すごい!
https://github.com/mrkn/matplotlib.rb
これも使うといい感じに可視化までしてくれます。
Saturating Forecasts
詳しい説明はこちら
https://facebook.github.io/prophet/docs/saturating_forecasts.html
df = Rover.read_csv("example_wp_log_R.csv")
df["cap"] = 8.5
m = Prophet.new(growth: "logistic")
m.fit(df)
future = m.make_future_dataframe(periods: 365)
future["cap"] = 8.5
forecast = m.predict(future)
トレンドがのchange points
fig = m.plot(forecast)
m.add_changepoints_to_plot(fig.gca, forecast)
特別な日の設定
holiday列とds列を持つデータフレームを作成します。過去のデータに含まれるすべての事象と、予測したい将来の事象を含めます。
playoffs = Rover::DataFrame.new(
"holiday" => "playoff",
"ds" => ["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 = Rover::DataFrame.new(
"holiday" => "superbowl",
"ds" => ["2010-02-07", "2014-02-02", "2016-02-07"],
"lower_window" => 0,
"upper_window" => 1
)
holidays = playoffs.concat(superbowls)
m = Prophet.new(holidays: holidays)
m.fit(df)
国別の祝日を入れることもできる
m = Prophet.new
m.add_country_holidays(country_name: "US")
m.fit(df)
季節性も設定できる。
m = Prophet.new(weekly_seasonality: false)
m.add_seasonality(name: "monthly", period: 30.5, fourier_order: 5)
forecast = m.fit(df).predict(future)
他にも色々な機能があります!本当に便利ですね。。