🎓 レベル:標準 | 重要度:A(必須)
📎 前提:ランダムウォークと単位根 | 関連:訓練・検証・テストと交差検証(機械学習)
要点(BLUF)
- 予測精度は RMSE(大外れに敏感)・MAE(平均的なズレに頑健)・MAPE(割合・スケール非依存だが 0 付近で不安定)で測ります。
- 時系列CVは順序を保つ:訓練は必ずテストより過去(ウォークフォワード/拡大窓)。普通の k-fold は未来から過去への情報漏洩で楽観的になります。
- 必ず素朴予測(前回値・季節素朴)をベースラインに。それより良くて初めてモデルに意味があります。
1. 予測の評価指標
予測 と実測 の誤差 を、3通りに集約します。
- RMSE:二乗するので大外れに敏感。外れを重く罰したいとき。
- MAE:絶対値なので外れに頑健。「平均してどれくらいズレるか」。
- MAPE:誤差を実測で割る割合。単位に依らず比較できるが、 が 0 付近だと発散・不安定。
import numpy as np
y_true = np.array([100, 102, 101, 105, 110, 108.0])
y_pred = np.array([ 98, 103, 104, 102, 109, 111.0])
e = y_pred - y_true
rmse = np.sqrt(np.mean(e**2)); mae = np.mean(np.abs(e)); mape = np.mean(np.abs(e/y_true))*100
print(f"RMSE={rmse:.3f}(大外れに敏感) MAE={mae:.3f}(平均的ズレ) MAPE={mape:.2f}%(割合)")
出力:
RMSE=2.345(大外れに敏感) MAE=2.167(平均的ズレ) MAPE=2.08%(割合)
出力の意味:RMSE が MAE より大きいのは、二乗が大きめの誤差を強く効かせるから。両者の差が開くほど「たまに大きく外す」傾向を示します。MAPE は「平均して実測の約2%ズレる」とスケール非依存に言えます。目的(大外れを嫌うか・割合で見たいか)で指標を選びます。
2. なぜ普通の k-fold はダメか:未来の情報漏洩
時系列は順序が本質。ところがふつうの k-fold(行をシャッフル/ランダム分割)は、テスト時点より未来のデータを訓練に入れてしまいます。「未来を見て過去を当てる」のは現実の予測ではありえず、評価が楽観的になります。正しくは TimeSeriesSplit(拡大窓)で、訓練を常にテストより過去に限ります。
import numpy as np
from sklearn.model_selection import TimeSeriesSplit, KFold
idx = np.arange(12)
print("TimeSeriesSplit(正しい): 訓練は常にテストより前")
for k, (tr, te) in enumerate(TimeSeriesSplit(n_splits=4).split(idx)):
print(f" fold{k}: train={tr.min()}..{tr.max()} test={te.min()}..{te.max()}")
print("KFold(誤り): テストより未来が訓練に混入=情報漏洩")
leak = 0
for k, (tr, te) in enumerate(KFold(n_splits=4).split(idx)):
future_in_train = int((tr > te.min()).sum()); leak += future_in_train
print(f" fold{k}: test={te.min()}..{te.max()} 未来なのに訓練にある点数={future_in_train}")
print(f" → 未来漏洩した点の総数={leak}")
出力:
TimeSeriesSplit(正しい): 訓練は常にテストより前
fold0: train=0..3 test=4..5
fold1: train=0..5 test=6..7
fold2: train=0..7 test=8..9
fold3: train=0..9 test=10..11
KFold(誤り): テストより未来が訓練に混入=情報漏洩
fold0: test=0..2 未来なのに訓練にある点数=9
fold1: test=3..5 未来なのに訓練にある点数=6
fold2: test=6..8 未来なのに訓練にある点数=3
fold3: test=9..11 未来なのに訓練にある点数=0
→ 未来漏洩した点の総数=18
出力の意味:TimeSeriesSplit は訓練範囲が常にテストより前(拡大窓で 0..3 → 0..5 → …)。一方 KFold は、たとえば fold0 でテストが時点 〜 なのに、訓練に未来の 9 点(時点3以降)が混ざります——合計 18 点の未来漏洩。これで測った精度は本番より良く見えるだけの幻です。同じ理由で、標準化や特徴量も訓練データだけで作ります(全データで作ると未来情報が漏れる)。
3. ウォークフォワード・バックテストとベースライン
実務の検証はバックテスト:過去のある時点に立ち、そこまでの情報だけで次を予測 → 時間を1歩進めて繰り返す。そして必ず素朴予測をベースラインに置きます。
- 素朴予測(naive):次は前回値 。
- 季節素朴(seasonal naive):次は1周期前 。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib # 日本語ラベル用
rng = np.random.default_rng(3)
n, period = 120, 12; t = np.arange(n)
y = 50 + 0.05*t + 8*np.sin(2*np.pi*t/period) + rng.normal(0, 1.0, n) # 季節が強い系列
start = 60
pred_naive, pred_snaive, actual, times = [], [], [], []
for i in range(start, n):
hist = y[:i] # 過去だけで予測(未来は見ない)
pred_naive.append(hist[-1]) # 素朴:前回値
pred_snaive.append(hist[-period]) # 季節素朴:1周期前
actual.append(y[i]); times.append(i)
actual = np.array(actual)
rmse_naive = np.sqrt(np.mean((np.array(pred_naive) - actual)**2))
rmse_snaive = np.sqrt(np.mean((np.array(pred_snaive) - actual)**2))
print(f"1期先予測 RMSE: 素朴(前回値)={rmse_naive:.3f} 季節素朴(1周期前)={rmse_snaive:.3f}")
plt.figure(figsize=(9, 4))
plt.plot(t, y, color="gray", lw=1, label="実測")
plt.plot(times, pred_snaive, "o-", ms=3, color="C1", label="季節素朴予測(1周期前)")
plt.axvline(start, ls=":", color="k"); plt.xlabel("時点 t"); plt.legend()
plt.title("ウォークフォワード・バックテスト(過去だけで1期先を予測)")
plt.tight_layout(); plt.show()
出力:
1期先予測 RMSE: 素朴(前回値)=3.315 季節素朴(1周期前)=1.710
出力の意味:季節が強いこの系列では、季節素朴(RMSE 1.71)が素朴(3.32)の半分の誤差。季節を無視した「前回値」は、毎ステップ季節の波を跨いで外すからです。どちらが勝つかはデータ次第(トレンドが強ければ前回値が勝つことも)——だからこそ複数のベースラインを必ず試し、新しいモデルはベースラインを上回って初めて価値があると判断します。図では季節素朴の予測(橙)が実測(灰)の波によく追随しています。
まとめ(Phase 1)
第1章で時系列の土台が揃いました——分解で構造を見て(時系列データと分解)、定常性と ACF/PACF で依存を測り(定常性と自己相関)、単位根を見極めて差分で定常化し(ランダムウォークと単位根)、順序を保った CV とベースラインで honest に評価する(本ノート)。次章では、この ACF/PACF の指紋を持つ ARIMA モデルで、依存構造を実際にモデル化して予測します。
⚠️ よくある誤解
- 「k-fold をそのまま使ってよい」ではない:時系列ではシャッフル=未来漏洩。TimeSeriesSplit(ウォークフォワード)を使います。
- 「MAPE が万能」ではない: が 0 付近・負だと不安定/非対称。需要が0を取るデータでは RMSE/MAE や対称版(sMAPE)を検討。
- 「前処理は全データでしてよい」ではない:標準化・欠測補完・特徴量も訓練のみで。全データで作ると未来情報が漏れます。
- 「指標が良ければ良いモデル」ではない:必ず素朴予測と比べる。ベースライン未満なら、そのモデルは無意味です。
関連ノート
- ランダムウォークと単位根
- AR・MAモデル(次章・依存構造のモデル化)
- バックテストと予測の評価(発展的なバックテスト)
- 訓練・検証・テストと交差検証(機械学習・CVの基礎)
- 第1章 時系列の基礎 目次
- 時系列分析・予測テキスト 全体目次