Prophet 第2回 天の下のすべてのことには時がある
タイトルはユダヤのコヘレトの書からの引用です。
観測されるものは目に見えますが、その裏側に流れている法則や因果は目に見えません。
でも人は見えない法則を信じているのです。
分析というのは、データの裏側にある法則を見つけ出す作業とも言えます。
時系列予測アルゴリズムProphetの使い方解説2回目です。
私たちは業務で時系列予測をおこなうシステムを開発していますが、
特に売上予測をする際には曜日や祝日、近隣のイベントなど様々な外部要因が影響する場合があります。
今日は外部変数の取り扱いについて紹介します。
前回Prophetアルゴリズムを紹介したように
Prophetでは年単位や月、週単位の周期性をデータから分析して予測をすることができます。
目的となる変数について何かしらの関係性がある事象がわかっている場合、外部変数として使うことができます。
例えば、休日などの条件がビールの売上に影響を与えるなどです。
影響を持つ変数を専門的には説明変数(regressor)と言います。
Prophetに説明変数を登録して予測する方法を説明していきます。
1 疑似データの作成
1週ごとの日付
from datetime import datetime, timedelta
def generate_weekly_dates(start_date_str, num_weeks):
start_date = datetime.strptime(start_date_str, '%Y-%m-%d')
date_list = []
for i in range(num_weeks):
current_date = start_date + timedelta(weeks=i)
date_list.append(current_date.strftime('%Y-%m-%d'))
return date_list
# 2025年1月1日から1年間(52週)の日付リストを生成
weekly_dates_2025 = generate_weekly_dates('2025-01-01', 52)
weekly_dates_2025
売上のダミーデータを作ります。それらしい値をGeminiに作ってもらいました。
今回は学校の夏休みの効果があると仮定しますので、夏休み冬休みのカラムを作ります。
import pandas as pd
ur = [100,110,105,115,120,110,100,95,105,110,125,130,120,110,105,110,115,120,135,140,130,120,115,110,100,90,80,150,160,170,180,190,180,170,160,150,140,130,120,110,100,90,80,70,80,90,100,110,120,130,140,150]
data = pd.DataFrame({'ds': pd.to_datetime(weekly_dates_2025), 'y': ur})
# 休日効果を追加
data['summer_holiday'] = 0
data.loc[(data['ds'] >= '2025-07-23') & (data['ds'] <= '2025-08-31'), 'summer_holiday'] = 1
data['winter_holiday'] = 0
data.loc[(data['ds'] >= '2025-12-24') & (data['ds'] <= '2026-01-05'), 'winter_holiday'] = 1
data.loc[(data['ds'] >= '2024-12-24') & (data['ds'] <= '2025-01-05'), 'winter_holiday'] = 1
データはこんな感じです
data.plot(x='ds', grid=True)
休み前のテスト期間の落ちっぷりと夏休みのテンションの対比が出ていて良い感じです。
2. 学習
Prophetで学習します。
from prophet import Prophet
import matplotlib.pyplot as plt
import plotly.offline as py
import plotly.graph_objs as go
# モデルの学習
model = Prophet(holidays=None)
model.add_regressor('summer_holiday')
model.add_regressor('winter_holiday')
model.fit(data)
3. 予測
学習出来たら、予測してみます。
# 予測期間の設定
future = model.make_future_dataframe(periods=365)
future['summer_holiday'] = 0
future.loc[(future['ds'] >= '2026-07-23') & (future['ds'] <= '2026-08-31'), 'summer_holiday'] = 1
future['winter_holiday'] = 0
future.loc[(future['ds'] >= '2025-12-24') & (future['ds'] <= '2026-01-05'), 'winter_holiday'] = 1
future.loc[(future['ds'] >= '2026-12-24') & (future['ds'] <= '2027-01-05'), 'winter_holiday'] = 1
future.loc[data.index,['winter_holiday', 'summer_holiday']]=data[['winter_holiday', 'summer_holiday']]
# 予測の実行
forecast = model.predict(future)
予測結果を見てみます。
# 結果の可視化
fig = model.plot(forecast)
# Plotlyでインタラクティブなグラフを作成
py.init_notebook_mode()
trace = go.Scatter(x=forecast['ds'], y=forecast['yhat'], name="予測値")
trace2 = go.Scatter(x=data['ds'], y=data['y'], name="実測値")
layout = go.Layout(title='売上予測')
fig = go.Figure(data=[trace, trace2], layout=layout)
py.iplot(fig)
青実線が予測平均で、薄い青の領域がノイズ分(標準偏差σ)の揺らぎを合わしています。
7月あたりから急激に予測値が伸びていて、良い感じです。
疑似データは2025年の12月までしか作っていないのですが、2026年以降も予測値が作られていることがわかると思います。
2025年と同様に2026年7月には夏休みが来るので同様の上昇がみられます。
このように、特定の日や範囲の効果を指定することでfitさせるときに別扱いとなります。
どのくらいの強さの効果があるかはデータから推定してくれます。
今回のブログでは、外部変数について説明しました。
次も時系列関連で何か書こうと思います。
Discussion