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分