Facebook Prophetによる時系列予測 — 加法モデルで手軽に高精度予測

「来月の売上を予測してほしい」「来年のユーザー数はどのくらいになりそうか」— ビジネスの現場では、こうした時系列予測の要求が日常的に発生します。しかし、ARIMA/SARIMAモデルは定常性の判定やパラメータ選択に統計的な知識を要求し、多くのビジネスアナリストにとってハードルが高いのが現実です。

Prophetは、Facebookの研究チームが2017年に公開した時系列予測ツールで、「ドメイン知識を持つアナリストが、統計の専門家でなくても高品質な予測を生成できる」ことを目標に設計されました。ARIMAが「時系列の統計的構造」をモデル化するのに対し、Prophetは「人間が理解しやすい成分(トレンド、季節性、祝日)の加法的組み合わせ」でモデル化します。

Prophetを理解することで、以下のような場面で活用できます。

  1. ビジネスKPIの予測 — 売上、PV数、ユーザー数などの将来予測を、週次・月次の季節性と祝日効果を考慮して行う
  2. キャパシティプランニング — サーバー負荷やインフラ需要の予測で、成長の飽和やトレンドの変化点を自動検出する
  3. 予測結果の解釈と説明 — 予測の各成分(トレンド、季節性、祝日効果)を分解して可視化し、ステークホルダーに説明する

本記事の内容

  • 実務での時系列予測の課題とProphetの設計思想
  • Prophetの加法モデル(trend + seasonality + holidays + error)
  • 各コンポーネントの数学的定式化
  • 変化点(changepoint)の自動検出
  • Pythonでの基本的な使い方
  • パラメータチューニングの指針
  • クロスバリデーションによる評価
  • SARIMAとの比較

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

実務での時系列予測の課題

ARIMAの現場での課題

SARIMAモデルは理論的に優れた手法ですが、実務で大量の時系列を予測する場面では以下のような課題があります。

  1. 定常性の確認と差分次数の決定: ADF検定を行い、適切な $d$, $D$ を選択する必要がある
  2. ACF/PACFの解釈: 特に実データではパターンが曖昧で、AR/MA次数の決定に経験が必要
  3. パラメータ空間の探索: $(p,d,q)(P,D,Q)_s$ の組み合わせが膨大
  4. 祝日や特殊イベントの処理: ARIMAモデルに外生変数として追加するには手動の設定が必要
  5. 欠損値への対応: ARIMAは等間隔のデータを前提とし、欠損値の処理が煩雑

Prophetの設計思想

Prophetはこれらの課題に対して、以下の設計思想で対処します。

  • 解釈可能な成分分解 — トレンド、季節性、祝日効果という人間が理解しやすい成分に分解
  • ドメイン知識の注入が容易 — 「トレンドの上限は○○」「この日は祝日」といった知識を直接パラメータに反映
  • デフォルト設定で十分な精度 — 最小限の設定で実用的な予測が得られ、必要に応じて調整可能
  • 欠損値・不等間隔データに対応 — 回帰モデルベースなので、時間軸の連続性を前提としない

この設計思想を踏まえて、Prophetのモデル構造を数学的に見ていきましょう。

Prophetの加法モデル

基本構造

Prophetは、時系列 $y(t)$ を以下の加法モデルで表現します。

$$ \begin{equation} y(t) = g(t) + s(t) + h(t) + \varepsilon_t \end{equation} $$

ここで、

  • $g(t)$: トレンド関数 — 非周期的な長期変化を捉える
  • $s(t)$: 季節性関数 — 周期的な変動パターン(年次、週次など)
  • $h(t)$: 祝日・イベント効果 — 不規則に発生する特定日の影響
  • $\varepsilon_t$: 誤差項 — モデルで捉えられない不規則な変動

この構造は、STL分解($x_t = T_t + S_t + R_t$)と類似していますが、Prophetでは各成分にパラメトリックなモデルを当てはめる点が異なります。STLが「データから成分を抽出する」分解手法であるのに対し、Prophetは「成分のパラメトリックモデルをデータにフィットさせる」予測手法です。

各成分の数学的な定式化を順に見ていきましょう。まず、最も重要なトレンド関数から始めます。

トレンド関数 $g(t)$

区分的線形トレンド(Piecewise Linear Growth)

最も基本的なトレンドモデルは、区分的線形関数です。時間軸上の変化点(changepoints) $s_1, s_2, \dots, s_S$ で傾きが変わります。

$$ \begin{equation} g(t) = (k + \bm{a}(t)^\top \bm{\delta}) \cdot t + (m + \bm{a}(t)^\top \bm{\gamma}) \end{equation} $$

ここで、

  • $k$: 初期成長率(初期の傾き)
  • $m$: オフセット(切片)
  • $\bm{\delta} = (\delta_1, \dots, \delta_S)^\top$: 各変化点での傾きの変化量
  • $\bm{a}(t)$: 指示関数ベクトル。$a_j(t) = 1$ if $t \geq s_j$, else $0$
  • $\bm{\gamma}$: 連続性を保つための調整項

$\bm{a}(t)^\top \bm{\delta}$ は、時刻 $t$ までに発生した全ての変化点の傾き変化量を足し合わせたものです。つまり、時刻 $t$ における傾きは $k + \sum_{j: s_j \leq t} \delta_j$ となります。

$\bm{\gamma}$ は、変化点で関数が連続になるように決まります。$j$ 番目の変化点での連続性条件から、

$$ \gamma_j = -s_j \delta_j $$

直感的に言えば、変化点 $s_j$ で傾きが $\delta_j$ だけ変わると、そのままでは関数が不連続になるため、切片を $\gamma_j$ だけ調整して連続性を保っているのです。

ロジスティック成長トレンド(Logistic Growth)

市場規模やユーザー数など、成長に上限(キャリング・キャパシティ)がある場合は、ロジスティック関数を使います。

$$ \begin{equation} g(t) = \frac{C(t)}{1 + \exp(-(k + \bm{a}(t)^\top \bm{\delta})(t – (m + \bm{a}(t)^\top \bm{\gamma})))} \end{equation} $$

ここで $C(t)$ はキャリング・キャパシティで、時間とともに変化することも許容されます。例えば、インターネットの普及率の上限は人口に比例するため、人口が増えれば上限も上がります。

ロジスティック成長はS字型の曲線を描きます。初期は指数的に成長し、上限 $C$ に近づくにつれて成長が鈍化します。

変化点の自動検出

Prophetはデフォルトで、データの最初の80%の範囲に25個の変化点候補を等間隔に配置し、スパース化正則化(Laplace事前分布)を用いて実質的に有効な変化点を自動選択します。

変化点の変化量 $\delta_j$ に対して、Laplace事前分布を設定します。

$$ \delta_j \sim \text{Laplace}(0, \tau) $$

ハイパーパラメータ $\tau$(Prophetでは changepoint_prior_scale)が小さいほど $\delta_j$ がゼロに近くなり、傾きの変化が抑制されます(トレンドが滑らかになる)。$\tau$ が大きいほど、傾きの変化が許容されます(トレンドが柔軟になる)。

  • $\tau$ が小さすぎる → トレンドの変化を見逃す(underfitting)
  • $\tau$ が大きすぎる → ノイズをトレンドとして拾ってしまう(overfitting)

デフォルト値は $\tau = 0.05$ で、多くのケースで良い結果を与えます。

トレンドの定式化を理解したところで、次に季節性の表現方法を見ていきましょう。

季節性関数 $s(t)$

フーリエ級数による表現

Prophetは季節性をフーリエ級数で近似します。周期 $P$ の季節性は、

$$ \begin{equation} s(t) = \sum_{n=1}^{N} \left(a_n \cos\left(\frac{2\pi nt}{P}\right) + b_n \sin\left(\frac{2\pi nt}{P}\right)\right) \end{equation} $$

で表されます。$N$ はフーリエ次数で、大きいほど複雑な季節パターンを表現できます。

なぜフーリエ級数を使うのでしょうか?フーリエ級数は任意の周期関数を近似できるという強力な性質を持つため、季節パターンの形状について事前に仮定を置く必要がありません。正弦波のような単純な季節性も、鋸歯状の複雑な季節性も、十分な次数があれば表現可能です。

デフォルト設定

Prophetのデフォルトでは、

  • 年次季節性: $P = 365.25$日、$N = 10$(20個のパラメータ)
  • 週次季節性: $P = 7$日、$N = 3$(6個のパラメータ)

年次季節性のフーリエ次数 $N = 10$ は、週単位よりも細かいパターンまで表現できることを意味します。週次季節性の $N = 3$ は、曜日ごとのパターン(平日と週末の違いなど)を十分に捉えられる設定です。

フーリエ次数の影響

$N$ を大きくすると、

  • より複雑な季節パターンを捉えられる(表現力の向上)
  • 過学習のリスクが高まる(ノイズに対するロバスト性の低下)

$N$ を小さくすると、

  • 季節パターンが滑らかに制約される(ロバスト性の向上)
  • 複雑な季節パターンを捉えられない(表現力の低下)

Prophetは季節性の係数 $(a_n, b_n)$ に対しても正規事前分布を設定し、正則化を行います。

$$ a_n, b_n \sim \mathcal{N}(0, \sigma_s^2) $$

$\sigma_s$(seasonality_prior_scale)が大きいほど季節パターンの振幅が大きくなることを許容します。

季節性の表現を理解したところで、Prophetのもう一つの特徴的な成分である祝日効果を見ていきましょう。

祝日・イベント効果 $h(t)$

定式化

祝日やイベントの効果は、各祝日 $i$ に対する指示関数と効果量の積として表現されます。

$$ \begin{equation} h(t) = \sum_{i=1}^{L} \kappa_i \cdot \mathbb{1}_{t \in D_i} \end{equation} $$

ここで、

  • $D_i$: 祝日 $i$ が影響する日の集合(祝日当日に加え、前後数日を含めることが可能)
  • $\kappa_i$: 祝日 $i$ の効果量
  • $L$: 祝日の総数

例えば、クリスマスの影響が12月24〜26日に及ぶ場合、$D_{\text{Christmas}} = \{12/24, 12/25, 12/26\}$ のように指定します。

祝日効果のパラメータにも事前分布が設定されます。

$$ \kappa_i \sim \mathcal{N}(0, \nu^2) $$

$\nu$(holidays_prior_scale)を大きくすると、祝日の効果が大きくなることを許容します。

祝日効果の利点

ARIMAモデルで祝日効果を扱うには、外生変数(SARIMAX)として手動でダミー変数を作成する必要がありましたが、Prophetでは祝日リストを渡すだけで自動的にモデルに組み込まれます。

日本の祝日のように年によって日付が変わる祝日(春分の日など)も、年ごとに正確な日付を指定できます。

ここまでProphetの理論的な構造を見てきました。次に、実際にPythonでProphetを使った予測を実装してみましょう。

Pythonでの基本的な使い方

AirPassengersデータでの予測

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
import warnings
warnings.filterwarnings('ignore')

# AirPassengersデータの準備
from statsmodels.datasets import get_rdataset
data = get_rdataset("AirPassengers").data
data.columns = ['time', 'passengers']

# Prophetの入力フォーマット(ds列とy列が必要)
df = pd.DataFrame({
    'ds': pd.date_range('1949-01-01', periods=len(data), freq='MS'),
    'y': data['passengers'].values.astype(float)
})

# 訓練/テスト分割
train = df[df['ds'] < '1959-01-01']
test = df[df['ds'] >= '1959-01-01']

# Prophetモデルの作成とフィッティング
model = Prophet(
    yearly_seasonality=True,     # 年次季節性
    weekly_seasonality=False,    # 週次季節性(月次データなので不要)
    daily_seasonality=False,     # 日次季節性(月次データなので不要)
    changepoint_prior_scale=0.05,  # トレンドの柔軟性
    seasonality_mode='multiplicative'  # 乗法的季節性
)
model.fit(train)

# 予測(テスト期間 + 24か月先)
future = model.make_future_dataframe(periods=len(test) + 24, freq='MS')
forecast = model.predict(future)

# プロット
fig, axes = plt.subplots(2, 1, figsize=(12, 8))

# 予測結果
axes[0].plot(train['ds'], train['y'], 'o', markersize=3, label='Train')
axes[0].plot(test['ds'], test['y'], 'o', markersize=3, color='black', label='Test')
axes[0].plot(forecast['ds'], forecast['yhat'], linewidth=1.5,
             color='red', label='Forecast')
axes[0].fill_between(forecast['ds'], forecast['yhat_lower'], forecast['yhat_upper'],
                     color='red', alpha=0.1)
axes[0].set_title('Prophet Forecast — AirPassengers')
axes[0].legend()

# テスト期間の拡大
test_forecast = forecast[forecast['ds'].isin(test['ds'])]
axes[1].plot(test['ds'], test['y'], 'o-', markersize=4, label='Actual')
axes[1].plot(test_forecast['ds'], test_forecast['yhat'], 'o-',
             markersize=4, color='red', label='Predicted')
axes[1].fill_between(test_forecast['ds'],
                     test_forecast['yhat_lower'], test_forecast['yhat_upper'],
                     color='red', alpha=0.1)
axes[1].set_title('Test Period Detail')
axes[1].legend()

plt.tight_layout()
plt.show()

# 精度指標
y_true = test['y'].values
y_pred = test_forecast['yhat'].values
mae = np.mean(np.abs(y_true - y_pred))
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
rmse = np.sqrt(np.mean((y_true - y_pred) ** 2))
print(f"MAE  = {mae:.2f}")
print(f"MAPE = {mape:.2f}%")
print(f"RMSE = {rmse:.2f}")

Prophetの予測結果から、以下の特徴が読み取れます。

  1. 季節パターンの再現: 乗法的季節性モード (seasonality_mode='multiplicative') を使用したため、トレンドの上昇に伴って季節変動の振幅も大きくなっており、AirPassengersデータの特性をよく捉えています。
  2. 予測区間: 薄い赤の帯で表示される予測区間は、予測ホライズンが長くなるほど広がっています。Prophetの予測区間はMCMCサンプリングまたはMAP推定に基づく不確実性を反映しています。
  3. デフォルト設定でも合理的な予測 — 最小限のパラメータ設定(季節性モードの指定のみ)で実用的な精度が得られています。

成分の可視化

Prophetの最大の利点の一つは、予測を構成要素に分解して可視化できることです。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
from statsmodels.datasets import get_rdataset
import warnings
warnings.filterwarnings('ignore')

# データ準備
data = get_rdataset("AirPassengers").data
data.columns = ['time', 'passengers']
df = pd.DataFrame({
    'ds': pd.date_range('1949-01-01', periods=len(data), freq='MS'),
    'y': data['passengers'].values.astype(float)
})

# モデル
model = Prophet(yearly_seasonality=True, weekly_seasonality=False,
                daily_seasonality=False, seasonality_mode='multiplicative')
model.fit(df)

future = model.make_future_dataframe(periods=24, freq='MS')
forecast = model.predict(future)

# 成分プロット
fig = model.plot_components(forecast, figsize=(12, 8))
plt.tight_layout()
plt.show()

成分プロットから、Prophetがデータをどのように理解しているかがわかります。

  1. トレンド成分: 区分的線形トレンドで長期的な上昇傾向を捉えています。変化点での傾きの変化も反映されています。
  2. 年次季節性: 月別の季節パターンが明確に表示されています。乗法モデルでは、このパターンが「トレンドの何倍」という比率として解釈されます。夏季にピーク(+20〜30%程度)、冬季に谷(-20%程度)というパターンが読み取れます。

この成分分解の可視化は、ビジネスのステークホルダーへの説明に非常に有用です。「全体の成長トレンドは年率○%で、夏季は平均より○%高い」といった説明が容易になります。

パラメータチューニング

主要なハイパーパラメータ

Prophetの主要なハイパーパラメータとその影響を整理します。

パラメータ デフォルト 影響
changepoint_prior_scale 0.05 トレンドの柔軟性。大きい→柔軟、小さい→滑らか
seasonality_prior_scale 10 季節性の振幅。大きい→大きな季節効果を許容
holidays_prior_scale 10 祝日効果の大きさ。大きい→大きな祝日効果を許容
seasonality_mode ‘additive’ ‘additive’ or ‘multiplicative’
changepoint_range 0.8 変化点の探索範囲(データの先頭何%まで)
n_changepoints 25 変化点候補の数

changepoint_prior_scaleの影響

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
from statsmodels.datasets import get_rdataset
import warnings
warnings.filterwarnings('ignore')

# データ準備
data = get_rdataset("AirPassengers").data
data.columns = ['time', 'passengers']
df = pd.DataFrame({
    'ds': pd.date_range('1949-01-01', periods=len(data), freq='MS'),
    'y': data['passengers'].values.astype(float)
})

scales = [0.001, 0.05, 0.5, 5.0]

fig, axes = plt.subplots(2, 2, figsize=(14, 8))
axes = axes.flatten()

for idx, scale in enumerate(scales):
    model = Prophet(changepoint_prior_scale=scale,
                    yearly_seasonality=True, weekly_seasonality=False,
                    daily_seasonality=False, seasonality_mode='multiplicative')
    model.fit(df)

    future = model.make_future_dataframe(periods=24, freq='MS')
    forecast = model.predict(future)

    axes[idx].plot(df['ds'], df['y'], 'o', markersize=2, alpha=0.5)
    axes[idx].plot(forecast['ds'], forecast['yhat'], linewidth=1.5, color='red')
    axes[idx].fill_between(forecast['ds'], forecast['yhat_lower'],
                           forecast['yhat_upper'], color='red', alpha=0.1)
    axes[idx].set_title(f'changepoint_prior_scale = {scale}')
    axes[idx].set_ylabel('Passengers')

plt.tight_layout()
plt.show()

changepoint_prior_scaleの影響が明確に見て取れます。

  1. 0.001(左上): トレンドがほぼ直線で、データの非線形な成長パターンを捉えられていません。underfittingの状態です。
  2. 0.05(右上): デフォルト値で、トレンドの変化を適度に捉えています。バランスの取れた設定です。
  3. 0.5(左下): トレンドがかなり柔軟で、データの細かい変動にも追従しています。
  4. 5.0(右下): トレンドがデータのノイズにまで追従してしまい、overfittingの兆候が見られます。将来の予測の不確実性も大きくなっています。

クロスバリデーション

Prophetの組み込みCV

Prophetは時系列のクロスバリデーション(CV)機能を内蔵しており、予測精度の客観的な評価が可能です。

時系列CVでは、「訓練期間の最後を cutoff として、そこから horizon 先まで予測し、実際の値と比較する」操作を、cutoff をずらしながら繰り返します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
from prophet.diagnostics import cross_validation, performance_metrics
from statsmodels.datasets import get_rdataset
import warnings
warnings.filterwarnings('ignore')

# データ準備
data = get_rdataset("AirPassengers").data
data.columns = ['time', 'passengers']
df = pd.DataFrame({
    'ds': pd.date_range('1949-01-01', periods=len(data), freq='MS'),
    'y': data['passengers'].values.astype(float)
})

# モデルのフィッティング
model = Prophet(yearly_seasonality=True, weekly_seasonality=False,
                daily_seasonality=False, seasonality_mode='multiplicative')
model.fit(df)

# クロスバリデーション
# initial: 最初の訓練期間の長さ
# period: cutoffをずらす間隔
# horizon: 予測ホライズン
df_cv = cross_validation(model, initial='730 days', period='180 days',
                         horizon='365 days')
print("Cross-validation results:")
print(df_cv.head(10))

# 性能指標
df_metrics = performance_metrics(df_cv, rolling_window=1)
print("\nPerformance Metrics:")
print(df_metrics[['horizon', 'mape', 'rmse', 'mae']].to_string())

# 予測ホライズンごとのMAPE
fig, ax = plt.subplots(figsize=(10, 5))
df_cv['horizon_days'] = (df_cv['ds'] - df_cv['cutoff']).dt.days
df_cv['ape'] = np.abs((df_cv['y'] - df_cv['yhat']) / df_cv['y'])

# 月ごとのMAPEを集計
df_cv['horizon_month'] = df_cv['horizon_days'] // 30 + 1
monthly_mape = df_cv.groupby('horizon_month')['ape'].mean() * 100

ax.bar(monthly_mape.index, monthly_mape.values, color='steelblue', alpha=0.7)
ax.set_xlabel('Forecast Horizon (months)')
ax.set_ylabel('MAPE (%)')
ax.set_title('MAPE by Forecast Horizon (Cross-Validation)')
plt.tight_layout()
plt.show()

クロスバリデーション結果から、予測精度に関する重要な知見が得られます。

  1. ホライズンごとのMAPE: 予測ホライズンが長くなるほどMAPEが増加する傾向が見られます。これは全ての予測モデルに共通する性質ですが、増加の速度がモデルの長期予測能力を反映しています。
  2. 月次データの場合: 1〜3か月先の短期予測では数%程度のMAPE、6〜12か月先の長期予測では10%程度以上のMAPEになることが一般的です。
  3. CV結果に基づくチューニング: changepoint_prior_scaleやseasonality_prior_scaleをグリッドサーチし、CV MAPEが最小になる設定を選ぶことで、データ適合的なチューニングが可能です。

SARIMAとの比較

最後に、同じデータに対してProphetとSARIMAの予測精度を比較します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
from statsmodels.datasets import get_rdataset
from statsmodels.tsa.statespace.sarimax import SARIMAX
import warnings
warnings.filterwarnings('ignore')

# データ準備
data = get_rdataset("AirPassengers").data
data.columns = ['time', 'passengers']
passengers = data['passengers'].values.astype(float)
time_index = pd.date_range('1949-01-01', periods=len(passengers), freq='MS')

# 分割
split_date = '1958-01-01'
n_test = sum(time_index >= split_date)

# --- Prophet ---
df_prophet = pd.DataFrame({'ds': time_index, 'y': passengers})
train_prophet = df_prophet[df_prophet['ds'] < split_date]
test_prophet = df_prophet[df_prophet['ds'] >= split_date]

model_prophet = Prophet(yearly_seasonality=True, weekly_seasonality=False,
                        daily_seasonality=False,
                        seasonality_mode='multiplicative',
                        changepoint_prior_scale=0.05)
model_prophet.fit(train_prophet)
future = model_prophet.make_future_dataframe(periods=n_test, freq='MS')
forecast_prophet = model_prophet.predict(future)
pred_prophet = forecast_prophet[forecast_prophet['ds'] >= split_date]['yhat'].values

# --- SARIMA ---
ts = pd.Series(np.log(passengers), index=time_index)
train_sarima = ts[ts.index < split_date]

sarima_model = SARIMAX(train_sarima, order=(0, 1, 1),
                       seasonal_order=(0, 1, 1, 12)).fit(disp=False)
pred_sarima_log = sarima_model.forecast(n_test)
pred_sarima = np.exp(pred_sarima_log.values)

# --- 比較 ---
y_true = passengers[time_index >= split_date]

fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(time_index[time_index < split_date], passengers[time_index < split_date],
        linewidth=1, color='gray', label='Train')
ax.plot(time_index[time_index >= split_date], y_true,
        linewidth=2, color='black', label='Actual')
ax.plot(time_index[time_index >= split_date], pred_prophet,
        linewidth=2, linestyle='--', color='blue', label='Prophet')
ax.plot(time_index[time_index >= split_date], pred_sarima,
        linewidth=2, linestyle='--', color='red', label='SARIMA')
ax.axvline(x=pd.Timestamp(split_date), color='gray', linestyle=':', alpha=0.5)
ax.set_title('Prophet vs SARIMA — AirPassengers')
ax.legend()
plt.tight_layout()
plt.show()

# 精度比較
for name, preds in [('Prophet', pred_prophet), ('SARIMA', pred_sarima)]:
    mae = np.mean(np.abs(y_true - preds))
    mape = np.mean(np.abs((y_true - preds) / y_true)) * 100
    rmse = np.sqrt(np.mean((y_true - preds) ** 2))
    print(f"{name:10s}: MAE={mae:.1f}, MAPE={mape:.1f}%, RMSE={rmse:.1f}")

ProphetとSARIMAの比較から、両手法の特性の違いが明確になります。

  1. 予測精度: AirPassengersデータのような比較的単純な構造(トレンド+季節性)のデータでは、SARIMAとProphetの予測精度は大きな差がないことが多いです。データの性質によってどちらが優れるかが変わります。
  2. 使い勝手: Prophetはパラメータ選択の手間が少なく、デフォルト設定でも合理的な結果が得られます。SARIMAは次数選択やモデル診断に専門知識が必要です。
  3. 解釈性: Prophetの成分分解は非常に直感的で、ビジネスユーザーへの説明に優れています。SARIMAのAR/MA係数は統計的な解釈に留まります。
  4. 柔軟性: Prophetは祝日効果や外部変数の追加が容易です。SARIMAXでも外生変数を追加できますが、設定がやや煩雑です。

使い分けの指針

観点 Prophet SARIMA
統計的知識 少なくてOK 必要
デフォルト性能 高い パラメータ選択次第
季節性の複数周期 容易(年次+週次等) 困難
祝日・イベント 組み込み機能あり 手動設定(SARIMAX)
欠損値 自動対応 前処理が必要
大量の時系列 自動化しやすい 個別チューニングが必要
理論的基盤 回帰ベース 確率過程ベース
予測区間の理論的保証 やや弱い 強い(正規性仮定下)

一般的な指針として、

  • 大量の時系列を一括処理する場合 → Prophet(自動化が容易)
  • 単一の時系列を精密に分析する場合 → SARIMA(理論的に厳密)
  • ビジネスアナリストが使う場合 → Prophet(使いやすさ重視)
  • 統計的な妥当性を重視する場合 → SARIMA(理論基盤が明確)

まとめ

本記事では、Facebook Prophetの理論と実装について詳しく解説しました。

  • 加法モデル: $y(t) = g(t) + s(t) + h(t) + \varepsilon_t$ という、人間が理解しやすい成分分解に基づくモデル
  • 区分的線形トレンド: 変化点で傾きが変わるトレンドモデル。Laplace事前分布による正則化で変化点を自動検出
  • フーリエ級数による季節性: 年次・週次など複数の季節性をフーリエ級数で柔軟に表現
  • 祝日・イベント効果: 特定日の影響を指示関数で簡潔にモデル化
  • クロスバリデーション: 時系列CVによる客観的な予測精度の評価が組み込みで可能

Prophetは「完璧な統計モデル」というよりは「実務で使いやすい予測ツール」として設計されています。理論的な厳密さはSARIMAに譲る部分もありますが、使いやすさ、解釈性、拡張性のバランスに優れています。

次のステップとして、以下の記事も参考にしてください。