交差検証 ── データを複数回分割して評価する手法
「精度95%でした」と言うとき、 1回のtrain/testだけだと運次第。 CVは「複数回試して平均」する保険です。 競技でも論文でも、 評価の信頼性は CV で担保するのが標準。
「テスト勉強」に例えるなら:
標準誤差も算出できる:$SE = \sigma_{\text{folds}} / \sqrt{k}$。 これで信頼区間付きで「精度 = $0.85 \pm 0.02$」と報告可能。
47都道府県データを 5-fold で分割すると:
1回だけ test=北海道〜青森とランダムに引いて R²=0.85 が出るより、 はるかに信頼性が高い数値です。
最小限のスニペットで動作確認できる例。 公的データ(SSDSE 等)を想定しています。
1 2 3 4 5 6 7 8 | from sklearn.model_selection import cross_val_score, KFold from sklearn.linear_model import Ridge kf = KFold(n_splits=5, shuffle=True, random_state=0) scores = cross_val_score(Ridge(alpha=1.0), X, y, cv=kf, scoring='r2') print(f"R² = {scores.mean():.3f} ± {scores.std():.3f}") # 5つの fold それぞれの R² を確認 print(scores) |
| 名前 | 用途 | 分割方法 |
|---|---|---|
| KFold | 標準 | ランダムにk分割 |
| StratifiedKFold | 分類(不均衡) | クラス比率を保つ |
| GroupKFold | 群あり | 同一群を同foldへ |
| TimeSeriesSplit | 時系列 | 過去→未来の順序 |
| LeaveOneOut | 少数データ | 1サンプルずつテスト |
| RepeatedKFold | 低分散評価 | k-foldをr回繰り返し |
| ShuffleSplit | 柔軟分割 | 毎回ランダム分割 |
ハイパラ調整したCVスコアをそのまま報告すると楽観バイアス。 Nested CV では外側で評価、 内側で調整:
1 2 3 4 5 6 7 | from sklearn.model_selection import cross_val_score, GridSearchCV, KFold inner = KFold(n_splits=3) outer = KFold(n_splits=5) grid = GridSearchCV(estimator, param_grid, cv=inner) scores = cross_val_score(grid, X, y, cv=outer) print(scores.mean(), scores.std()) |
外側5fold × 内側3fold = 15回学習。 計算重いが評価信頼性が桁違いに上がる。
| 名前 | 用途 | 分割方法 |
|---|---|---|
| KFold | 標準 | ランダムにk分割 |
| StratifiedKFold | 分類(不均衡) | クラス比率を保つ |
| GroupKFold | 群あり | 同一群を同foldへ |
| TimeSeriesSplit | 時系列 | 過去→未来の順序 |
| LeaveOneOut | 少数データ | 1サンプルずつテスト |
| RepeatedKFold | 低分散評価 | k-foldをr回繰り返し |
| ShuffleSplit | 柔軟分割 | 毎回ランダム分割 |
ハイパラ調整したCVスコアをそのまま報告すると楽観バイアス。 Nested CV では外側で評価、 内側で調整:
1 2 3 4 5 6 7 | from sklearn.model_selection import cross_val_score, GridSearchCV, KFold inner = KFold(n_splits=3) outer = KFold(n_splits=5) grid = GridSearchCV(estimator, param_grid, cv=inner) scores = cross_val_score(grid, X, y, cv=outer) print(scores.mean(), scores.std()) |
外側5fold × 内側3fold = 15回学習。 計算重いが評価信頼性が桁違いに上がる。