LESSON

ARIMA/SARIMAモデル

「まずは古典的だが強力な統計モデルから始めよう。ARIMAは時系列予測の基本中の基本だ。」

田中VPoEがホワイトボードにARIMAの数式を書き始める。

「自己回帰、差分、移動平均。この3つの組み合わせで驚くほど多くの時系列パターンをモデル化できる。季節成分を加えたSARIMAなら、Store Salesの週次パターンも捉えられる。」

ARIMAモデルの基本

ARIMA(AutoRegressive Integrated Moving Average)は、3つの要素で構成される。

ARIMA(p, d, q):
  AR(p): 自己回帰 - 過去p期間の値の線形結合
  I(d):  和分    - d回の差分で定常化
  MA(q): 移動平均 - 過去q期間の予測誤差の線形結合

各成分の意味

成分数式意味
AR(p)Y(t) = c + φ1Y(t-1) + … + φpY(t-p) + ε(t)過去の値が現在の値を決める
I(d)ΔdY(t)d回差分して定常化する
MA(q)Y(t) = c + ε(t) + θ1ε(t-1) + … + θqε(t-q)過去の予測誤差が現在の値に影響

パラメータの選定

方法1: ACF/PACFによる手動選定

Step 2で学んだACF/PACFの読み方を使う。

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# 1次差分 + 7日季節差分後のACF/PACF
diff_series = grocery.diff().diff(7).dropna()

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
plot_acf(diff_series, lags=28, ax=axes[0])
plot_pacf(diff_series, lags=28, ax=axes[1], method='ywm')
plt.tight_layout()
plt.show()

# PACFがラグ1で切れる → p=1
# ACFがラグ1で切れる → q=1
# 差分回数 → d=1
# → ARIMA(1, 1, 1)が候補

方法2: auto_arima(自動選定)

from pmdarima import auto_arima

# 自動パラメータ選定
model = auto_arima(
    grocery,
    seasonal=True,
    m=7,                    # 季節周期(週次)
    d=None,                 # 自動判定
    D=None,                 # 季節差分も自動判定
    start_p=0, max_p=3,
    start_q=0, max_q=3,
    start_P=0, max_P=2,
    start_Q=0, max_Q=2,
    information_criterion='aic',
    trace=True,             # 探索過程を表示
    error_action='ignore',
    suppress_warnings=True,
    stepwise=True
)

print(model.summary())
# 最適モデル例: SARIMA(1,1,1)(0,1,1,7)

SARIMAモデル

SARIMA(Seasonal ARIMA)は、ARIMAに季節成分を追加したモデル。

SARIMA(p, d, q)(P, D, Q, s):
  (p, d, q): 非季節成分のパラメータ
  (P, D, Q, s): 季節成分のパラメータ
  s: 季節周期

SARIMAの実装

from statsmodels.tsa.statespace.sarimax import SARIMAX

# データの準備
train_data = grocery[:'2017-07-31']
test_data = grocery['2017-08-01':'2017-08-15']

# SARIMAモデルの構築
model = SARIMAX(
    train_data,
    order=(1, 1, 1),          # (p, d, q)
    seasonal_order=(0, 1, 1, 7),  # (P, D, Q, s)
    enforce_stationarity=False,
    enforce_invertibility=False
)

results = model.fit(disp=False)
print(results.summary())

# 予測
forecast = results.forecast(steps=15)
print("\n予測結果(最初の5日):")
print(forecast.head())

# 精度評価
from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np

mae = mean_absolute_error(test_data, forecast[:len(test_data)])
rmse = np.sqrt(mean_squared_error(test_data, forecast[:len(test_data)]))
mape = np.mean(np.abs((test_data - forecast[:len(test_data)]) / test_data)) * 100

print(f"\nMAE: {mae:.2f}")
print(f"RMSE: {rmse:.2f}")
print(f"MAPE: {mape:.2f}%")

残差診断

# 残差の診断プロット
results.plot_diagnostics(figsize=(14, 10))
plt.tight_layout()
plt.show()

# 確認すべきポイント:
# 1. 残差のACFに有意な自己相関が残っていないか
# 2. 残差が正規分布に従っているか(Q-Qプロット)
# 3. 残差に時間的パターンが残っていないか

# Ljung-Box検定
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_test = acorr_ljungbox(results.resid, lags=[7, 14, 21], return_df=True)
print("Ljung-Box検定:")
print(lb_test)
# p値 > 0.05 なら残差に有意な自己相関なし

ARIMAの限界

限界説明
線形性非線形な関係を捉えられない
外部変数SARIMAXで対応可能だが柔軟性に欠ける
長期予測予測期間が長くなるほど精度が急激に低下
複数系列1,782系列それぞれに個別モデルが必要
計算コストパラメータ探索に時間がかかる

まとめ

項目ポイント
ARIMA(p,d,q)自己回帰 + 差分 + 移動平均の統計モデル
SARIMA季節成分を追加。Store Salesでは(P,D,Q,7)
パラメータ選定ACF/PACF手動 or auto_arima自動
残差診断Ljung-Box検定、Q-Qプロットで確認

チェックリスト

  • ARIMA(p,d,q)の各パラメータの意味を説明できる
  • SARIMAの季節パラメータを理解した
  • auto_arimaによる自動選定を実行できる
  • 残差診断の方法を理解した

次のステップへ

ARIMAの基本を押さえたところで、次はFacebook Prophetを使い、祝日効果やトレンド変化点を自動的に捉えるモデルを構築しよう。

推定読了時間: 30分