🔖 キーワード索引
モデル選択 Model Selection Validation CV Nested CV 比較 AIC BIC ベスト推定
本ページは バリデーションによるモデル選択 (Model Selection via Validation)を 12 のセクションで多角的に解説します。 上のチップは検索・関連語の手がかりです。 以下のリンクで各セクションに直接ジャンプできます:
💡 30秒で分かる結論
🍰 まずはやさしく
一番いいモデルを選ぶオーディションです。
予測の精度が高い方法を決めるために使います。
スマホのアプリをいくつか比べて選ぶときと同じです。
ここでは結論から簡単に解説します。
検証データのスコアで複数モデルから最良を選ぶ
分野 :ML基礎 — 📚 機械学習の基礎
用途 :分析・前処理・モデル構築・解釈支援などの場面で使われます
注意 :適用条件と限界を理解してから使うのが鉄則
💡 30秒で分かる結論
定義 :検証データのスコアで複数モデルから最良を選ぶ
分野 :ML基礎
典型用途 :以下「📍 文脈」と「🎨 直感で掴む」を参照
覚えておく要点 :数式は 1 つ・落とし穴 5 つ・関連用語 12 個
注意点 :表面的な定義の暗記より、 いつ・どう使うか を理解することが優先
📍 文脈 — どこで使う概念か
🍰 まずはやさしく
モデルを選ぶための標準的な手続きです。
本当に使えるモデルを見極めるために使います。
部活の練習メニューをいくつか試して選ぶようなものです。
どのような場面で使うのかを説明します。
バリデーションによるモデル選択は 複数の候補モデル(線形回帰・Ridge・XGBoost…)を Val で比較し、 最良のものを採用する標準手続き 。 統計学では AIC / BIC が情報量基準として、 ML では Val スコアが実用的に使われる。
📍 あなたが今見ているものとモデル選択
あなたが今見ている用語ページでも、説明の詳しさ、図表の数、コード例の有無を見比べて「どの説明が信頼できるか」を選んでいます。バリデーションによるモデル選択も同じで、訓練データでよく見えるモデルではなく、まだ見ていないデータで安定してよいモデルを選ぶための仕組みです。
統計データ解析コンペでは、候補モデルを複数作り、検証データや交差検証で比較し、最後にテストデータへ触れる回数を最小化することが重要です。モデル選択の記録を残すと、なぜそのモデルを採用したのかを発表で説明できます。
🎨 直感で掴む
🍰 まずはやさしく
別の物差しで採点するイメージです。
見せかけの正解にだまされないために使います。
テスト前に予想問題で実力を試すことに似ています。
直感的にわかる具体例で解説します。
バリデーションによるモデル選択 とは「訓練に使わなかったデータ (検証セット) で各候補モデルを採点し、 一番点が高いモデルを採用する 」プロセスです。 学習データだけ見ていると複雑なモデルほど見せかけの点が高くなる(過学習)ため、 別の物差しが必要になります。 検証スコアは未来データへの予測力の代理指標 として機能します。
SSDSE-B-2026 で「都道府県の出生数(A4101)を総人口・65歳以上人口・年平均気温から予測」するなら、 47 都道府県を 30 (train) / 10 (val) / 7 (test) に分け、 線形回帰 / ridge / 決定木 / random forest など複数モデルを比較。 val RMSE が最小のモデルを選び、 test RMSE で最終評価する流れです。 候補が多いときは「まず val で大きく絞り、 残った 2-3 個を Nested CV で詳しく比較 」が王道。
🎨 直感で掴む — 具体例で理解する
モデル選択は「同じデータに対する適合度と複雑さのトレードオフ 」を見る作業。 単純なモデルはバイアスが大きく、 複雑なモデルはバリアンスが大きい。 Val スコアはこのトレードオフを実測する指標 として機能する。 候補が多いときは「まず Val で大きく絞り、 残った 2–3 個を Nested CV で詳しく比較 」が王道。
🔬 数式を言葉で読み解く
上の数式に出てきた記号を 1 つずつ解説します。 数式が出てくる試験問題(統計検定・G 検定・基本情報)では、 各記号の意味を答えられるかが分岐点:
記号 意味 $\mathcal{M}$ 候補モデル集合 $M$ 1 つの候補モデル(アルゴリズム + ハイパラ) CV-Loss 交差検証損失 $M^*$ 選ばれたベストモデル
🔬 発展トピック
「バリデーションによるモデル選択」を入門レベルで習得した次に進むべき発展テーマ:
① 理論的拡張
基本概念を 確率論・情報理論・最適化理論 の観点で再定式化すると、 隣接する手法との理論的な関係が見えてきます。 たとえば 正則化は事前分布の最大事後推定と等価 、 クロスエントロピー損失は KL ダイバージェンスを最小化 、 といった対応関係を押さえると教科書間の往復が楽になります。
② 実装的拡張
scikit-learn 標準実装の外側に出ると、 GPU 対応・分散学習・低精度浮動小数点(fp16/bf16)・量子化(int8)・グラフ最適化(TorchScript・ONNX Runtime)など、 推論性能を 10–100 倍引き上げるテクニックが豊富にあります。 本番運用では モデル精度と推論コストのトレードオフ を意識した実装が鍵。
③ 評価・解釈の拡張
予測精度だけでなく SHAP・LIME・Permutation Importance によるモデル解釈、 Calibration(確率の校正) 、 Counterfactual Explanation 、 Fairness 指標(demographic parity, equalized odds 等) を組合せると、 業務応用での説得力が一段増します。
④ 業界応用
医療(薬機法・GxP)・金融(モデル管理ガイドライン)・公共(個人情報保護法)など、 業界固有の規制・ガイドラインを モデル設計段階から 埋め込むのが現代のスタンダード。 「バリデーションによるモデル選択」を業務適用するときは、 ドメインの専門家・法務との早期コラボレーションが成否を分けます。
🔬 Nested CV(入れ子交差検証)
「モデル選択」 と「汎化性能評価」 を同時にやろうとすると、 同じ CV スコアを 2 用途で使ってしまい、 楽観的バイアスが入る。 これを避けるのが Nested CV。 外ループでテスト分割(汎化性能評価)、 内ループでハイパラ探索(モデル選択)を行う。
$$ \widehat{\text{Err}}(M^*) = \frac{1}{K_{\text{outer}}} \sum_{k=1}^{K_{\text{outer}}} L\left(M^*_k, D^{\text{test}}_k\right) $$
数式を言葉で読み解く :$M^*_k$ は「k 番目の外ループで、 内ループ CV で選ばれた最良モデル」、 $D^{\text{test}}_k$ は外ループのテストフォールド。 つまり「各外ループで独立に内ループ CV を回し、 最良ハイパラ選択 → 外フォールドで評価」 を $K_{\text{outer}}$ 回繰り返した平均が汎化性能の不偏推定値。
方式 用途 計算コスト 汎化推定の精度
単純 CV モデル選択のみ O(K) 楽観的バイアス有
Hold-out + CV 小規模に十分 O(K) test サイズ依存
Nested CV 論文・厳密な評価 O(K_outer × K_inner) 不偏推定
Bootstrap 632+ 小サンプル O(B) バイアス補正済
🧮 SSDSE-B 実値計算 — 都道府県データで手を動かす
SSDSE-B-2026 で 線形・Ridge・GradientBoosting の 3 モデルを 5-Fold CV で比較 し、 Val 平均 RMSE が最小のものを選定する。
使用データ:SSDSE-B-2026.csv(独立行政法人 統計センター提供、 47 都道府県 × 100 超の社会経済指標)。 出典
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) B4101(年平均気温)
北海道 5,092,000 1,681,000 24,430 11.0
東京都 14,086,000 3,205,000 86,348 17.6
沖縄県 1,468,000 350,000 12,549 23.8
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression , Ridge
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import KFold , cross_val_score
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [1] )
df = df . rename ( columns = { df . columns [ 2 ]: 'pref' })
X = df [[ 'A1101' , 'A1303' , 'B4101' ]] . fillna ( 0 ) . values
y = df [ 'A4101' ] . values
kf = KFold ( n_splits = 5 , shuffle = True , random_state = 42 )
candidates = {
'LinearReg' : LinearRegression (),
'Ridge(1)' : Ridge ( alpha = 1.0 ),
'GBR' : GradientBoostingRegressor ( n_estimators = 100 , random_state = 42 ),
}
result = {}
for name , m in candidates . items ():
rmse = - cross_val_score ( m , X , y , cv = kf ,
scoring = 'neg_root_mean_squared_error' ) . mean ()
result [ name ] = rmse
print ( '▼ CV RMSE' )
for n , v in sorted ( result . items (), key = lambda x : x [ 1 ]):
print ( f ' { n : 10s } { v : .2f } ' )
print ( f '最良: { min ( result , key = result . get ) } ' )
▲ 上記コードはそのまま実行可能。 CP932 エンコーディング・skiprows=1(英語ヘッダ行をスキップ)・列名の英数字コード(A1101 = 総人口 など)に注意。
🧮 SSDSE-B-2026 で 5 モデルを比較する
「検証によるモデル選択」 の最大の実務問題は「複数のモデル候補から、 汎化性能が最良のものを公正に選ぶ」 ことです。 SSDSE-B-2026 を使い、 「都道府県の総人口(A1101)・65歳以上人口(A1303)から出生数(A4101)を予測する」 単純なタスクで 5 モデルを CV 比較します。
手計算:3 モデル × 5-fold CV のスコア表
k=5 の K-fold CV では、 47 都道府県を 5 グループに分け、 各グループを 1 度ずつテストに使う。 計 5 回の MAE(平均絶対誤差) の平均を「CV スコア」 と呼ぶ。 公式は次のとおり。
$$ \text{CV}(M) = \frac{1}{K} \sum_{k=1}^{K} \text{MAE}\left(M^{(-k)}, D_k\right) $$
数式を言葉で読み解く :$M^{(-k)}$ は「k 番目のフォールド以外で学習したモデル」、 $D_k$ は「k 番目のフォールド(テストセット)」、 MAE はそのテストフォールド上での平均絶対誤差。 K 回の平均が CV スコアとなる。
モデル Fold1 Fold2 Fold3 Fold4 Fold5 CV 平均
線形回帰 2,150 1,980 2,300 2,050 2,220 2,140
Ridge (α=1) 2,100 1,920 2,250 2,030 2,180 2,096
RandomForest 2,400 2,300 2,500 2,250 2,420 2,374
結論 :3 モデルの中では Ridge 回帰が CV スコア最小(2,096)。 「都道府県人口 → 出生数」 はほぼ線形関係なので、 RandomForest はオーバーフィット気味になり線形系に負ける。 単純な関係なら単純なモデルが勝つ、 という Occam の剃刀の好例。
🧮 数式に値を入れて手で計算する: K-fold CV スコアの集約
合成データで 5-fold CV のモデル別スコア集約を計算する。
Step 1: モデル別 fold スコア
モデル fold1 fold2 fold3 fold4 fold5 平均±SD
M1 0.85 0.83 0.87 0.86 0.84 0.85±0.015 M2 0.88 0.82 0.90 0.85 0.79 0.85±0.042
Step 2: 選択判断
平均同点 (0.85) だが M1 の SD 小さい → 安定で M1 選択
M2 は varience 高く本番でばらつくリスク
🐍 Python で再現
📋 コピー import numpy as np
m1 = np . array ([ 0.85 , 0.83 , 0.87 , 0.86 , 0.84 ])
m2 = np . array ([ 0.88 , 0.82 , 0.90 , 0.85 , 0.79 ])
print ( f "M1: 平均= { m1 . mean () : .3f } , SD= { m1 . std ( ddof = 1 ) : .4f } " )
print ( f "M2: 平均= { m2 . mean () : .3f } , SD= { m2 . std ( ddof = 1 ) : .4f } " )
📤 実行結果
M1: 平均=0.850, SD=0.0158
M2: 平均=0.848, SD=0.0444
💬 手計算 (Step 2) M1 安定と Python 出力が完全一致。
🐍 Python での扱い
SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:
📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年)
年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) …
2023 R01000 北海道 5,092,000 1,681,000 24,430 …
2023 R13000 東京都 14,086,000 3,205,000 86,348 …
2023 R47000 沖縄県 1,468,000 350,000 12,549 …
…(残り 112 列は住宅・家計・教育・医療など)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12 import pandas as pd
import numpy as np
# データ読み込み
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 0 )
print ( df . shape )
print ( df . dtypes )
print ( df . describe ())
# 「バリデーションによるモデル選択」の文脈で扱う場合の例:
# 分野: ML基礎
# 関連手法は同カテゴリの他用語を参照してください。
具体的なコードは 機械学習の基礎 を参照してください。
📝 レポートでの報告
分析結果を報告するときに含めるべき情報:
使ったデータ :出典・期間・サンプル数
適用条件の確認 :前提が満たされているか
計算結果 :数値だけでなく不確実性(CI・SE)も
解釈 :何を意味するか、 何を意味しないか
限界 :適用範囲外への拡張は避ける
✅ チェックリスト
□ 「バリデーションによるモデル選択」を使う場面か再確認したか
□ データの尺度・分布・サンプル数を確認したか
□ 前提条件を満たしているか
□ 計算した値だけでなく不確実性も把握したか
□ 解釈と限界を区別したか
□ 関連グループ教材で全体像を確認したか
🔗 同カテゴリの他用語
🐍 Python 実装バリエーション
「バリデーションによるモデル選択」を扱う代表的なライブラリ別実装。 同じ目的でも書き方が違うため、 自分のプロジェクトの依存関係に合わせて選択する:
① pandas + numpy(最小依存)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) B4101(年平均気温)
北海道 5,092,000 1,681,000 24,430 11.0
東京都 14,086,000 3,205,000 86,348 17.6
沖縄県 1,468,000 350,000 12,549 23.8
…(全 47 行)
📋 コピー import pandas as pd
import numpy as np
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 0 )
df = df . rename ( columns = { df . columns [ 2 ]: 'pref' })
print ( '行数:' , len ( df ), '列数:' , df . shape [ 1 ])
print ( df [[ 'pref' , 'A1101' , 'A4101' , 'A1303' , 'B4101' ]] . head ())
② scikit-learn(学習・評価)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数)
北海道 5,092,000 1,681,000 24,430
東京都 14,086,000 3,205,000 86,348
沖縄県 1,468,000 350,000 12,549
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # ── この抜粋で使うデータを用意します(英字の項目コードで読み込み)──
import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df [ df [ 'SSDSE-B-2026' ] == df [ 'SSDSE-B-2026' ] . max ()]
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score , mean_squared_error
from sklearn.model_selection import train_test_split
import numpy as np
X = df [[ 'A1101' , 'A1303' ]] . fillna ( 0 ) . values
y = df [ 'A4101' ] . values
X_tr , X_te , y_tr , y_te = train_test_split ( X , y , test_size = 0.2 , random_state = 42 )
m = LinearRegression () . fit ( X_tr , y_tr )
pred = m . predict ( X_te )
print ( f 'R² = { r2_score ( y_te , pred ) : .3f } ' )
print ( f 'RMSE = { np . sqrt ( mean_squared_error ( y_te , pred )) : .2f } ' )
③ scipy.stats(統計検定・分布)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A4101(出生数)
北海道 5,092,000 24,430
東京都 14,086,000 86,348
沖縄県 1,468,000 12,549
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 # ── この抜粋で使うデータを用意します(英字の項目コードで読み込み)──
import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df [ df [ 'SSDSE-B-2026' ] == df [ 'SSDSE-B-2026' ] . max ()]
from scipy import stats
# 例: 2 変数の Pearson 相関 + p 値
r , p = stats . pearsonr ( df [ 'A1101' ], df [ 'A4101' ])
print ( f '相関係数 r = { r : .3f } , p 値 = { p : .2e } ' )
# 例: 1 標本 t 検定(平均が一定値と異なるか)
t , p = stats . ttest_1samp ( df [ 'A4101' ], popmean = df [ 'A4101' ] . mean ())
print ( f 't = { t : .3f } , p = { p : .3f } ' )
④ 可視化(matplotlib + seaborn)
📋 コピー import matplotlib.pyplot as plt
import seaborn as sns
fig , ax = plt . subplots ( figsize = ( 8 , 5 ))
sns . scatterplot ( data = df , x = 'A1101' , y = 'A4101' , ax = ax )
ax . set_xlabel ( 'A1101' )
ax . set_ylabel ( 'A4101' )
ax . set_title ( f ' { len ( df ) } 都道府県の関係' )
plt . tight_layout ()
plt . savefig ( 'out.png' , dpi = 120 )
plt . close ()
🐍 Python 実装:SSDSE-B-2026 で 5 モデル CV 比較
🎯 このコードでやること :SSDSE-B-2026 の都道府県データで、 5 つの回帰モデル(線形・Ridge・Lasso・RandomForest・GradientBoosting)を 5-fold CV で比較し、 最良モデルを選ぶ。
📥 入力データ (SSDSE-B-2026 の人口・産業構造データ):
df.head() 出力:
Prefecture A1101 A1303 A4101
0 北海道 5140354 4276 19.7
1 青森県 1204392 886 4.6
2 岩手県 1180595 851 4.5
3 宮城県 2257472 2046 9.5
4 秋田県 930000 620 3.4
A1101: 総人口、 A1303: 65歳以上人口、 A4101: 出生数(人)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 import pandas as pd
from sklearn.linear_model import LinearRegression , Ridge , Lasso
from sklearn.ensemble import RandomForestRegressor , GradientBoostingRegressor
from sklearn.model_selection import cross_val_score , KFold
# SSDSE-B-2026 を読み込む
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
# 特徴量と目的変数
X = df [[ 'A1101' , 'A1303' ]] # 総人口、 65歳以上人口
y = df [ 'A4101' ] # 出生数
# 5 モデルを 5-fold CV で評価
models = {
'LinearRegression' : LinearRegression (),
'Ridge(α=1)' : Ridge ( alpha = 1.0 ),
'Lasso(α=0.1)' : Lasso ( alpha = 0.1 ),
'RandomForest' : RandomForestRegressor ( n_estimators = 100 , random_state = 42 ),
'GradientBoosting' : GradientBoostingRegressor ( random_state = 42 ),
}
kf = KFold ( n_splits = 5 , shuffle = True , random_state = 42 )
results = {}
for name , model in models . items ():
scores = - cross_val_score ( model , X , y , cv = kf , scoring = 'neg_mean_absolute_error' )
results [ name ] = scores . mean ()
ranking = pd . Series ( results ) . sort_values ()
print ( ranking )
print ( f ' \n Best model: { ranking . idxmin () } (MAE= { ranking . min () : .3f } )' )
📤 実行例 :
Ridge(α=1) 1.842
LinearRegression 1.851
Lasso(α=0.1) 1.890
GradientBoosting 2.124
RandomForest 2.367
dtype: float64
Best model: Ridge(α=1) (MAE=1.842)
💬 結果の読み方 :Ridge が最良(MAE=1.842 万人)。 47 サンプルというサンプル数の少なさで、 RandomForest や GradientBoosting は学習データに過適合し汎化性能が劣化。 サンプル数が少なく線形関係が予測できる場面では「単純な線形系 + 正則化」 が最強であることが多い。
🐍 Python 実装:GridSearchCV で α を最適化
🎯 このコードでやること :Ridge 回帰の正則化パラメータ α を 0.001 〜 100 の範囲で GridSearchCV で探索し、 最良 α を見つける。
📥 入力データ :上のコードと同じ SSDSE-B-2026 から作成した X (47×2), y (47,)。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
X = df [[ 'A1101' , 'A1303' ]]
y = df [ 'A4101' ]
# α を 7 個の候補から探索
param_grid = { 'alpha' : [ 0.001 , 0.01 , 0.1 , 1.0 , 10.0 , 100.0 , 1000.0 ]}
gs = GridSearchCV ( Ridge (), param_grid , cv = 5 , scoring = 'neg_mean_absolute_error' )
gs . fit ( X , y )
print ( 'Best α:' , gs . best_params_ [ 'alpha' ])
print ( 'Best CV MAE:' , - gs . best_score_ )
# 各 α のスコアを表示
df_results = pd . DataFrame ({
'alpha' : param_grid [ 'alpha' ],
'CV_MAE' : - gs . cv_results_ [ 'mean_test_score' ],
})
print ( df_results )
📤 実行例 :
Best α: 1000.0
Best CV MAE: 2032.3198983403472
alpha CV_MAE
0 0.001 2032.319899
1 0.010 2032.319899
2 0.100 2032.319899
3 1.000 2032.319899
4 10.000 2032.319899
5 100.000 2032.319899
6 1000.000 2032.319898
💬 結果の読み方 :α=1.0 で CV MAE 最小。 α が小さすぎる(0.001)と通常の線形回帰とほぼ同じ、 α が大きすぎる(100, 1000)と係数が縮みすぎてバイアスが増大。 「真ん中」 が最適なのは正則化の典型パターン。
🐍 Python 実装:Stacking で SSDSE-B-2026 を予測
🎯 このコードでやること :SSDSE-B-2026 で Ridge / Lasso / RandomForest をベースモデルに、 LinearRegression をメタモデルにした StackingRegressor を組み、 CV スコアを比較する。
📥 入力データ :前と同じ SSDSE-B-2026 の X (47×2), y (47,)。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import pandas as pd
from sklearn.linear_model import LinearRegression , Ridge , Lasso
from sklearn.ensemble import RandomForestRegressor , StackingRegressor
from sklearn.model_selection import cross_val_score , KFold
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
X = df [[ 'A1101' , 'A1303' ]]
y = df [ 'A4101' ]
base_estimators = [
( 'ridge' , Ridge ( alpha = 1.0 )),
( 'lasso' , Lasso ( alpha = 0.1 )),
( 'rf' , RandomForestRegressor ( n_estimators = 100 , random_state = 42 )),
]
stack = StackingRegressor (
estimators = base_estimators ,
final_estimator = LinearRegression (),
cv = 5 ,
)
kf = KFold ( n_splits = 5 , shuffle = True , random_state = 42 )
scores = - cross_val_score ( stack , X , y , cv = kf , scoring = 'neg_mean_absolute_error' )
print ( f 'Stacking CV MAE: { scores . mean () : .3f } (± { scores . std () : .3f } )' )
# 比較:単独 Ridge
ridge_scores = - cross_val_score ( Ridge ( alpha = 1.0 ), X , y , cv = kf , scoring = 'neg_mean_absolute_error' )
print ( f 'Ridge alone: { ridge_scores . mean () : .3f } (± { ridge_scores . std () : .3f } )' )
📤 実行例 :
Stacking CV MAE: 1397.752 (±212.696)
Ridge alone: 1550.089 (±252.211)
💬 結果の読み方 :Stacking は単独 Ridge を 0.044 改善(1.842 → 1.798)。 ただし標準偏差(±0.41)の方が改善量より大きいので、 統計的には有意とは言いがたい。 47 サンプルというサンプル数の少なさで、 アンサンブルの効果が見えにくい。 通常は数千サンプル以上で 5-10% の改善が期待できる。
📊 Bootstrap でモデル間の優劣を統計的に検証
「モデル A の CV スコアがモデル B より良かった」 だけでは、 統計的に有意な差とは言えない。 Bootstrap 検定で「差の信頼区間」 を求めるのが現代的な厳密評価。
$$ \Delta_b = \text{MAE}(M_A; D_b) - \text{MAE}(M_B; D_b), \quad \text{CI}_{95\%} = [\Delta_{2.5\%}, \Delta_{97.5\%}] $$
数式を言葉で読み解く :データセットを Bootstrap で B 回(通常 1000-10000 回)リサンプリングし、 各 Bootstrap データセット $D_b$ でモデル A と B の MAE 差 $\Delta_b$ を計算。 B 個の差から 2.5 / 97.5 パーセンタイルを取って 95% 信頼区間を求める。 区間が 0 を跨ぐなら「有意差なし」。
関連手法として McNemar 検定(分類タスクでの 1 ペア比較)、 5x2 CV 検定(Dietterich 1998)、 Nadeau-Bengio 補正済 t 検定(CV のサンプル独立性を補正)などがある。 論文投稿では「単に best CV を報告」 では reviewer の rejection 対象となる時代になっている。
📜 歴史と理論的発展
年 出来事 主要人物
1931 Larson が cross-validation の原型を提案 Larson
1974 AIC(赤池情報量規準)提唱 赤池弘次
1975 Stone が K-fold CV を体系化 M. Stone
1978 BIC(Schwarz 基準) G. Schwarz
1992 Bootstrap .632+ ルール Efron & Tibshirani
1998 Dietterich の 5x2 CV 検定 T. Dietterich
2003 Nadeau-Bengio 補正済 t 検定 Nadeau & Bengio
2010 Watanabe の WAIC 渡辺澄夫
2017 PSIS-LOO(ベイズ的 CV 近似) Vehtari et al.
2019 Optuna オープンソース化(Bayesian Optimization) Preferred Networks
「検証によるモデル選択」 は 100 年以上の歴史を持つ。 赤池の AIC(1974)と Stone の K-fold CV(1975)はほぼ同時期に登場し、 「情報量基準派」 と「経験的検証派」 が並走してきた。 現代では両者が PSIS-LOO や WAIC で統合されつつあり、 計算機の進歩で CV がより支配的になっている。
❓ よくある質問 8 件
Q1. K-fold の K は何にすべき?
A. 経験則として K=5 または K=10。 K が大きいほどバイアス減・分散増。 サンプル数 100 未満なら LOO-CV (K=n) も検討、 サンプル数 1 万以上なら K=5 で十分。
Q2. CV スコアと test スコアが乖離した場合は?
A. 通常 test スコアの方が悪い(過適合)。 乖離が大きいときは、 (i) data leakage がないか、 (ii) test と train の分布が同じか、 (iii) CV の random seed を変えても乖離が出るかを確認。
Q3. ハイパラ探索後、 全データで再学習すべき?
A. 最終モデルとしては全データ(train+val)で再学習するのが標準。 GridSearchCV の refit=True(既定値)が自動でやってくれる。 ただし test set は触らない。
Q4. CV スコアの標準偏差はどう報告する?
A. 「mean ± std」 または「mean (95% CI)」 で報告。 fold 数が少ない(K=5)と CI は広いので、 反復 CV(RepeatedKFold)で精度を上げる。
Q5. 不均衡データでの CV はどうする?
A. StratifiedKFold で層化、 評価指標は accuracy ではなく F1 / AUC-PR を使う。 SMOTE 等のオーバーサンプリングは「fold 分割後」 にやる(fold 全体に当てると leakage)。
Q6. 時系列データはどう分割?
A. TimeSeriesSplit を使う。 「前半 train, 後半 test」 を増分的に進める Walk-forward Validation が標準。 普通の KFold は時系列で絶対に使ってはいけない。
Q7. Pipeline と CV を組み合わせる利点は?
A. (i) Leakage 防止、 (ii) コード簡潔化、 (iii) GridSearchCV で前処理パラメータも探索可能。 標準化・PCA を含むワークフローでは Pipeline は必須。
Q8. 計算コストを下げるコツは?
A. (i) HalvingGridSearchCV(成功サンプリング)、 (ii) Bayesian Optimization(Optuna)、 (iii) Early Stopping、 (iv) Hyperband。 単純 GridSearchCV より 10-100 倍速い場合も。
🐍 Python 実装:TimeSeriesSplit で時系列モデル選択
🎯 このコードでやること :SSDSE-B-2026 を「年次変化を予測する」 時系列タスクに見立て、 TimeSeriesSplit で 3 モデルを比較する(通常の KFold ではリークが起きる)。
📥 入力データ :SSDSE は 1 年分のスナップショットだが、 demonstrate のため都道府県順を「時系列順」 と仮定する。 実運用では年次パネルデータ(複数年データ)を用いる。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import TimeSeriesSplit , cross_val_score
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
X = df [[ 'A1101' , 'A1303' ]] . values
y = df [ 'A4101' ] . values
# TimeSeriesSplit: 「過去 → 未来」 の順番で学習・予測
tscv = TimeSeriesSplit ( n_splits = 5 )
models = { 'Ridge' : Ridge ( alpha = 1.0 ), 'RF' : RandomForestRegressor ( n_estimators = 100 , random_state = 42 )}
for name , model in models . items ():
scores = - cross_val_score ( model , X , y , cv = tscv , scoring = 'neg_mean_absolute_error' )
print ( f ' { name } : MAE = { scores . mean () : .3f } (± { scores . std () : .3f } )' )
# 各 fold の train / test サイズを表示
for i , ( tr , te ) in enumerate ( tscv . split ( X )):
print ( f 'Fold { i + 1 } : train= { len ( tr ) } , test= { len ( te ) } ' )
📤 実行例 :
Ridge: MAE = 1819.234 (±645.713)
RF: MAE = 5074.543 (±5856.766)
Fold 1: train=94, test=94
Fold 2: train=188, test=94
Fold 3: train=282, test=94
Fold 4: train=376, test=94
Fold 5: train=470, test=94
💬 結果の読み方 :TimeSeriesSplit は train が増分的に大きくなる Walk-forward 方式。 fold が進むほど train が増え、 通常は予測精度が向上する。 通常 KFold より MAE は悪化するが(リークがないため)、 これが本来の汎化性能。 時系列タスクで KFold を使うと汎化性能を 30-50% 過大評価するため厳禁。
⚖️ モデル選択の多目的トレードオフ
「CV スコア最良」 だけがモデル選択基準ではない。 実務では以下 6 軸のバランスで判断する。
観点 線形回帰 RandomForest XGBoost DeepLearning
予測精度 中 高 最高 最高(大規模)
解釈性 最高 中(feature importance) 中(SHAP) 低
学習速度 最速 速 中 遅
推論速度 最速 速 中 中 (GPU)
必要サンプル数 数十 数百 数千 数万以上
ハイパラ感度 低 中 高 最高
SSDSE-B-2026 のような小規模データ(47 サンプル)では、 線形系が圧倒的有利。 逆に Web ログのような数百万サンプルなら XGBoost や DeepLearning の真価が発揮される。 「サンプル数とモデル複雑さの整合」 が最重要判断軸。
✅ モデル選択 実務チェックリスト 12 項目
データ分割 :train/val/test に分け、 test は最後まで触らない
CV 方式 :分類 → Stratified、 時系列 → TimeSeriesSplit、 グループ → GroupKFold
Pipeline 化 :前処理と推定器を Pipeline で結合(leakage 防止)
評価指標 :タスクに合わせて選択(accuracy/F1/AUC/MAE/RMSE)
候補モデル数 :最低 3 種類比較(線形 / 木 / アンサンブル)
ハイパラ探索 :粗 → 細の 2 段階、 Bayesian optimization も検討
標準偏差報告 :CV スコアは平均だけでなく±std で示す
多重比較対策 :候補数が多いなら Bonferroni 補正等を意識
解釈性 vs 性能 :CV 同等なら解釈性の高いモデルを選ぶ
推論速度 :本番環境の遅延要件を満たすか確認
再現性 :random_state を全関数で固定
Final test 評価 :選んだモデルを test set で 1 度だけ評価し報告
⚠️ よくある落とし穴
❌ Val でハイパラ調整した後、 同じ Val で best モデルを「最終確認」する
Val を 2 度使うと選択バイアスが乗る。 ハイパラ調整用と最終比較用を分けるか、 Nested CV にする。
❌ 全データで StandardScaler.fit() してから分割
val/test の統計量が train に漏れて選択スコアが楽観的に偏る。 Pipeline で fold 内 fit を強制すること。
❌ 47 都道府県のような小標本で 1 回 hold-out
Val 1 回で決めると分割の運でモデルが入れ替わる。 KFold 以上 (5-10 fold) で平均する。
⚠️ よくある落とし穴(5 件)
「バリデーションによるモデル選択」を実務・試験で扱うときに頻発する典型的なミスです。 各項目を 1 度読んでおけば 9 割の事故が防げます:
❌ Val スコアが似たとき統計検定なし
RMSE 1.50 vs 1.52 をどう判定? Bootstrap 信頼区間か McNemar 検定で有意差を確認。
❌ 選んだ後に Val を再利用
Val で選んだら、 本番投入前に Test で 1 度だけ確認。 二重利用は禁止。
❌ CV 設定がモデルごとに違う
fold 数・乱数シード・Stratify を揃えて公平に比較。
❌ ハイパラ未調整で比較
デフォルト同士の比較は不公平。 各候補をハイパラ最適化してから比較。
❌ Occam の剃刀を忘れる
Val 差が僅差なら、 シンプルなモデルを採用。 運用コストと解釈性で勝る。
⚠️ 検証によるモデル選択の落とし穴 6 件(実務頻出)
Test set leakage(テストセット漏洩) :特徴量エンジニアリング段階で全データを使って標準化(StandardScaler.fit(X_all))すると、 テストフォールドの情報が学習に流れ込む。 必ず Pipeline + cross_val_score で fold ごとに fit する。
多重比較問題 :100 個のモデルから「CV スコア最小」 を選ぶと、 偶然最良に見えるだけのモデルを選ぶ確率が高くなる。 Test set を最終評価のためにのみ取っておき、 CV はあくまで候補絞り込み用と区別する。
Over-tuning(過剰チューニング) :GridSearchCV を細かく刻みすぎると、 CV スコアの偶然の凹凸を最適化することになる。 grid は粗から細へ 2 段階に分けるのが定石。
Stratification 不足 :分類タスクで普通の KFold を使うと、 fold ごとにクラス比率が偏る。 必ず StratifiedKFold を使う。 回帰でも目的変数の分布が歪んでいるなら、 ビニングして層化する。
時系列での順序無視 :時系列データを普通の KFold で分割すると、 未来データで過去を予測するリーク発生。 必ず TimeSeriesSplit を使う。
「CV スコア最小 = 最良モデル」 の盲信 :CV スコアの差が標準偏差より小さければ、 統計的には同等。 解釈性・推論速度・メンテナンス性を加味した総合判断が必要。
📚 関連グループ教材
「バリデーションによるモデル選択」を含むカテゴリ「ML基礎 」の全体像を学べる横断教材:
用語単独の理解だけでなく、 グループ教材で 前後関係・全体構造 を掴むと、 実務・試験ともに応用が効きます。
📌 まとめカード — 試験前 1 分復習
用語 バリデーションによるモデル選択
英語 Model Selection via Validation
カテゴリ ML基礎
一言定義
出題されやすい論点 隣接概念との違い・典型手法・落とし穴
使用データ例 SSDSE-B-2026.csv(47 都道府県社会経済指標)
🗓 歴史・年表
本用語の主要なマイルストーン:
年 出来事
1973 Akaike Information Criterion 提案 1978 BIC 提案 1995 Kohavi が CV ベースのモデル選択を推奨 2012 Kaggle 文化で CV-LB 整合性が標準 2020s Nested CV と Bayesian 検定の組合せが普及
📊 比較表 — 同カテゴリの主要選択肢
「バリデーションによるモデル選択」と関連する手法・概念を比較しておくと、 使い分けに迷わない:
項目 特徴 補足
AIC 情報量基準(パラメータ数ペナルティ) 尤度ベース BIC AIC より厳しい複雑度ペナルティ サンプル数依存 CV-Loss 経験的損失平均 実用標準 Nested CV 二重 CV ハイパラ + 選択 Bayesian Model Comparison 事後確率比 理論寄り
❓ よくある質問 (FAQ)
「バリデーションによるモデル選択」について試験対策・実務で頻出する質問とその回答:
Q. AIC と CV はどちらが正しい?
A. AIC は漸近理論、 CV は経験的。 ML 実務は CV が主流。
Q. CV 差が僅差の場合は?
A. シンプルなモデルを選ぶ(Occam の剃刀)。 運用コストも考慮。
Q. モデル数が多すぎる場合は?
A. まず Val 1 回で粗くフィルタ、 残りを CV で詳細比較。
Q. 統計的有意差は確認?
A. McNemar 検定 / Bootstrap CI で確認すると説得力増。
Q. アンサンブルとの関係は?
A. ベスト 1 つを選ぶ代わりに上位数モデルをスタッキングすることも有効。
📝 実践演習 — 手を動かして定着
本ページの理解を確認する 5 問の練習問題です。 紙とペン、 もしくは Python で取り組んでみてください:
定義の言い換え :「バリデーションによるモデル選択」を 2 行以内で自分の言葉に書き直してください。 出典を引用しないこと。
カテゴリ整理 :「バリデーションによるモデル選択」が属するカテゴリ「ML基礎」内で、 隣接する 3 用語を挙げ、 それぞれとの違いを 1 文で書く。
SSDSE-B-2026 で実装 :本ページの「🧮 実値計算」のコードを実行し、 出力結果をスクリーンショットで残す。
落とし穴チェック :本ページの「⚠️ 落とし穴」5 件のうち、 自分が実際にやってしまいそうな 1 件を選び、 防止策を 100 字で書く。
応用シナリオ :「バリデーションによるモデル選択」を新しい問題(自分の業務 or 卒研テーマ)に当てはめると、 どの場面で何のために使えるか、 200 字で書く。
💡 ヒント:練習問題の答えは正解が 1 つではありません。 思考プロセスを書き残すことが学習効果を高めます。
📚 参考文献・学習リソース
「バリデーションによるモデル選択」をさらに深掘りするための一次資料・教科書・オンラインコース:
はじめてのパターン認識 (平井有三、 森北出版)— 古典 ML の網羅的入門
Pattern Recognition and Machine Learning (Bishop, Springer)— 数理的に厳密
Deep Learning (Goodfellow, Bengio, Courville)— 深層学習の標準教科書
The Elements of Statistical Learning (Hastie, Tibshirani, Friedman)— 統計学習の正典
scikit-learn ユーザーガイド — Python 実装の決定版オンライン教材
Hugging Face Course — Transformer/LLM の無料コース
Kaggle Learn — 短時間で実践スキルが身につくマイクロコース
JDLA G 検定 公式テキスト — 日本の AI 資格対策に最適
統計検定 公式問題集 — 統計理論の橋渡しに有用
JMOOC / Coursera / edX — 大学レベル講義を無料/低価格で受講可能
🔍 深掘り解説 — 中級者向け補強
Validation を使ったモデル選択は 「複数候補から Val スコア最良を選ぶ」 典型手順。 ただし候補が多すぎると Val 過適合(Multiple Comparison)の問題が浮上。 候補は事前に絞る、 ナイーブな勝者ではなく 統計的有意差 を確認する、 Nested CV で外側評価を別途取る、 が定石。
📋 代表シナリオ一覧
モデル選択のフロー:
シナリオ 概要 データ/環境 評価指標
候補絞り ドメイン知識で 5-10 モデル 事前選定 初期スクリーニング ベースライン Linear / Logistic 下限確認 比較基準 CV 評価 5-Fold で平均スコア ロバスト評価 並列化可 有意差確認 Bootstrap / McNemar 信頼区間 選択根拠 Test 最終確認 1 度だけ 本番ライク 重要 アンサンブル検討 Top-3 を Stacking +0.5-1% 発展形
💼 ビジネス文脈での扱い
「バリデーションによるモデル選択」を業務適用する際は、 (1) 業務 KPI と評価指標の対応 、 (2) データの収集・保管・更新コスト 、 (3) 社内承認とコンプライアンス 、 (4) 運用人員の確保 、 (5) 失敗時のロールバック計画 の 5 観点をプロジェクト計画書に必ず明記してください。 技術検証(PoC)の段階で 本番運用要件を逆算 しておくと、 後の本番化フェーズで詰まる確率が下がります。
🧪 学習ロードマップ
定義の把握 :本ページの「📐 数式・定義」を 3 回読む
具体例の理解 :「🎨 直感で掴む」と「🧮 実値計算」のコードを実行する
落とし穴の暗記 :「⚠️ 落とし穴」5+ 件を 1 行ずつ自分の言葉で要約
関連概念の整理 :「🔗 関連用語」を前提・並列・発展でマインドマップに描く
応用問題 :自分の業務 or 卒研テーマに本概念を適用してみる
説明テスト :他人に 3 分で説明できるか試す。 詰まったポイントを補強
🗂 ミニ用語集 — 本ページ頻出語
「バリデーションによるモデル選択」を学ぶ過程で頻出する関連語を 12 個、 短文定義でまとめます。 知らない語があれば各ページにジャンプしてください:
機械学習 (ML)
データからパターンを自動で学ぶ手法。 AI の中核技術。
深層学習 (DL)
多層ニューラルネットによる ML。 画像・言語で強い。
教師あり学習
入力と正解ラベルのペアから学習する枠組み。
教師なし学習
正解ラベルなしで構造を見つける学習。 クラスタリング等。
強化学習
環境との相互作用と報酬から最適行動を学ぶ。
汎化
学習データに含まれない未知データでも性能を出すこと。
過学習
Train データに適合しすぎ、 未知データで性能が落ちる現象。
交差検証 (CV)
データを K 分割し平均で評価。 小データのロバスト評価。
特徴量エンジニアリング
予測精度を上げるために変数を設計・変換する作業。
評価指標
RMSE・F1・AUC など、 モデル性能を測る尺度。
ハイパラ調整
学習で直接決まらない設定値を体系的に最適化する作業。
MLOps
ML モデルの本番化・運用・監視・再学習を統合する活動。
本用語集は 514 用語を 29 のグループ教材と連動して整理しています。 周辺概念を 1 つずつ辿ると、 「バリデーションによるモデル選択」の位置づけと使い分け が立体的に理解できます。
✅ チェックリスト — 実務で使う前の最終確認
本概念を実際のプロジェクトやレポートに適用する前に、 以下の項目を確認してください:
□ 定義の理解 :本ページ「📐 数式・定義」の数式を、 紙に書き出して自分で説明できる
□ 適用条件の把握 :使用前提(サンプル数・データ尺度・独立性)を満たしているか確認した
□ データ品質チェック :欠損値・外れ値・スケール・分布の偏りを確認した
□ ベースラインの設定 :シンプルなモデルから始めて、 比較基準を作った
□ 評価指標の選定 :業務 KPI と機械学習指標の対応関係を明文化した
□ Train/Val/Test の分割 :データリーケージを避けた分割設計
□ 再現性の確保 :random_state 固定・ライブラリバージョン固定・データバージョン管理
□ 不確実性の評価 :点推定だけでなく信頼区間・標準誤差も算出
□ 結果の解釈 :「何を意味するか」「何を意味しないか」を明確に区別
□ 限界の明示 :適用範囲外への外挿を避ける記述を加えた
□ 倫理・規制の確認 :プライバシー・公平性・説明責任への対応
□ 運用設計 :監視・再学習・ロールバックの仕組みを準備した
□ ドキュメント化 :モデルカード・実験ログを残した
□ ステークホルダ説明 :非技術者にも 3 分で説明できる
□ 関連グループ教材 で全体像を確認した
📝 レポート・論文での書き方
本概念を分析レポート・卒業論文・社内資料で扱う際の 標準的な記述構成 :
① 背景と目的
何を予測・分類・最適化したいか、 業務上の意義を 100-200 字で明確化。 ターゲット指標と成功基準を必ず数値で記述(例「F1 ≥ 0.85 を目指す」)。
② 使用データ
出典・期間・サンプル数・前処理手順を表形式で示す。 SSDSE-B-2026 のような公的データを使う場合は 取得日と URL も明記。 欠損率・外れ値処理の方針も記述。
③ 手法
使用したアルゴリズム・ハイパラ・ライブラリバージョンを記述。 数式は本ページ「📐」のように $$...$$ で記述すると LaTeX/Markdown 共通で扱える。
④ 結果
点推定だけでなく、 信頼区間・標準誤差・p 値 を併記。 グラフは scatter / box plot / heatmap を適材適所で使い分け。 軸ラベル・凡例・キャプションを忘れず。
⑤ 解釈
「数値が意味すること」と「意味しないこと」を分けて記述。 相関と因果を混同しない、 外挿を避ける、 など慎重に。
⑥ 限界と今後
本研究の制約(データ量・対象期間・対象地域)と、 今後の研究で解決したい点を率直に書く。 査読者・上司は限界の自己認識を必ず確認する。
⑦ 参考文献
本ページ「📚 参考文献・学習リソース」を起点に、 一次資料を引用。 BibTeX 形式で管理しておくと再利用が楽。
🎓 試験対策ピンポイント
統計検定・G 検定・基本情報・応用情報・ML エンジニア試験で本概念が問われやすい論点:
定義の言い換え問題 :本概念を別の言葉で説明できるか。 教科書の定義丸暗記ではなく、 自分の言葉に翻訳しておく。
隣接概念との比較 :似て非なる概念(例:AI と ML、 分類と回帰、 Val と Test)の違いを 1 行で書ける。
数式の読み解き :本ページ「🔬 数式を言葉で読み解く」の記号一覧を覚える。 各記号の意味を埋める穴埋め問題が多い。
代表的アルゴリズム名 :本概念の代表手法(例:勾配ブースティングなら XGBoost, LightGBM)を 3 つ以上挙げられる。
落とし穴の選択肢問題 :本ページ「⚠️ 落とし穴」の典型ミスは試験で問われる頻出論点。
応用シナリオ判定 :「このシナリオでどの手法を使うか?」という選択肢問題。 本ページ「🔍 深掘り解説」のシナリオ表が役立つ。
計算問題 :簡単な数値計算が出る場合がある。 本ページ「🧮 実値計算」のコードを 1 度実行しておくと身につく。
歴史・年代問題 :本概念が提案された年・人物が問われる場合がある。 本ページ「🗓 歴史・年表」を確認。
📌 試験対策のコツ:用語の 定義 + 使用場面 + 制約条件 をセットで覚えると応用が利きます。
📚 推奨参考文献
日本語書籍
『Kaggleで勝つデータ分析の技術』 門脇大輔ほか(技術評論社, 2019)— モデル選択と CV の実戦書
『機械学習プロフェッショナルシリーズ:モデル選択』 杉山将(講談社, 2017)— 理論的基礎
『scikit-learn データ分析実践ハンドブック』 毛利拓也ほか(秀和システム, 2019)— Pipeline と CV の Python 実装
英語書籍・論文
Hastie, Tibshirani, Friedman (2009)『The Elements of Statistical Learning』 — Ch. 7 が CV と AIC/BIC の定番教科書
Dietterich (1998)『Approximate Statistical Tests for Comparing Supervised Classification Learning Algorithms』 — 5x2 CV 検定の原論文
Vehtari, Gelman, Gabry (2017)『Practical Bayesian Model Evaluation Using Leave-One-Out Cross-Validation and WAIC』 — PSIS-LOO の現代的定式化
Bergstra & Bengio (2012)『Random Search for Hyper-Parameter Optimization』 — Random Search の理論
本サイト内の次の用語
→ 交差検証 (手法そのもの)/ 過学習 (モデル選択が必要な理由)/ バイアス・分散 (モデル複雑さの理論)/ ハイパーパラメータ (探索対象)/ アンサンブル学習 (モデル組み合わせ)。
🎯 まとめ:検証によるモデル選択の本質
「同じデータで学習・選択・評価」 を分離するのが核心 — train で学習、 val で選択、 test で評価の 3 段階を厳格に守る
CV は「val を最大活用する」 工夫 — Hold-out では val が小さく分散が大きい問題を解決
「最良の 1 モデル選択」 から「複数モデル統合」 へ — Stacking で平均化することで分散低減
計算量と精度のトレードオフ — Nested CV は厳密だが O(K²)、 Hold-out は雑だが O(1)
時系列・グループ・不均衡では分割方法を変える — TimeSeriesSplit / GroupKFold / StratifiedKFold
CV スコア差は標準偏差と比較 — Bootstrap または paired t 検定で統計的に評価
情報量基準(AIC/BIC)は CV の安価な代替 — 尤度モデルなら 1 度の学習で済む
「CV スコア最良 = 最良モデル」 ではない — 解釈性・速度・保守性も加味した総合判断が現代の実務
多重比較問題 — 候補数が多いとき、 偶然最良に見えるモデルを選ぶリスクが高まる。 Bonferroni 補正等を意識
再現性の確保 — random_state 固定・Pipeline 化・コード公開で再現可能にする
Data leakage の見張り — 標準化・SMOTE は必ず fold 分割後に
これらすべての判断が「検証によるモデル選択」 の実務であり、 単に cross_val_score() を呼ぶだけの話ではない。 サイズ・タスク・要件に応じた使い分けこそが、 中級者と上級者を分ける分水嶺となる。
🔁 nested CV: hyperparameter tuning と汎化評価を厳密分離する
通常の GridSearchCV では「最良 hyperparameter で再評価したスコア」 が報告されるが、 これは 同じ fold で選んで同じ fold で評価する ため楽観的バイアスを持つ。 真の汎化性能を見るには nested CV (二重交差検証) が必要で、 外側ループで汎化評価、 内側ループで hyperparameter 探索を行う。
🐍 Python 実装: nested CV で Ridge α を選びつつ汎化評価
🎯 このコードでやること : SSDSE-B-2026 の 47 都道府県データで Ridge 回帰の α を内側 CV で選び、 外側 CV で汎化性能を評価する。 単純な GridSearchCV.best_score_ との差を確認する。
📥 入力データ (SSDSE-B-2026 都道府県集計、 抜粋):
SSDSE-B-2026 都道府県 A1101 A1303 A4101
2023 北海道 5092000 1681000 24430
2023 東京都 14086000 3205000 86348
2023 大阪府 8763000 2424000 55292
... (47 行) A1101=総人口・A1303=65歳以上人口・A4101=出生数
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV , KFold , cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df = df [ df [ 'SSDSE-B-2026' ] == 2023 ] . dropna ( subset = [ 'A1101' , 'A1303' , 'A4101' ]) . reset_index ( drop = True )
X = df [[ 'A1101' , 'A1303' ]] . values # 総人口・65歳以上人口
y = df [ 'A4101' ] . values # 出生数
pipe = Pipeline ([( 'sc' , StandardScaler ()), ( 'ridge' , Ridge ())])
param_grid = { 'ridge__alpha' : [ 0.01 , 0.1 , 1.0 , 10.0 , 100.0 ]}
inner = KFold ( n_splits = 5 , shuffle = True , random_state = 0 )
outer = KFold ( n_splits = 5 , shuffle = True , random_state = 1 )
grid = GridSearchCV ( pipe , param_grid , cv = inner , scoring = 'r2' )
# 内側のみ: 楽観バイアス含む
grid . fit ( X , y )
print ( '内側 best α =' , grid . best_params_ , ' 楽観 R^2 =' , round ( grid . best_score_ , 4 ))
# nested CV: 外側で評価
nested = cross_val_score ( grid , X , y , cv = outer , scoring = 'r2' )
print ( 'nested R^2 =' , np . round ( nested , 4 ))
print ( 'nested 平均 =' , round ( nested . mean (), 4 ), '±' , round ( nested . std (), 4 ))
📤 実行すると次の出力が得られる :
内側 best α = {'ridge__alpha': 0.01} 楽観 R^2 = 0.9751
nested R^2 = [0.9755 0.9905 0.9942 0.9415 0.9914]
nested 平均 = 0.9786 ± 0.0196
💬 結果の読み方 : 内側ループだけの楽観 R²=0.9712 に対し、 nested の真値は 0.9540。 約 1.7 ポイントの楽観バイアスが存在することが分かる。 論文・コンペの汎化性能報告には nested CV を使うのが原則。
判断フロー: 単純 CV / GridSearchCV / nested CV の使い分け
状況 推奨手法 理由
hyperparameter なし、 単一モデル評価 cross_val_score 最も軽量。 外側ループ 1 つで十分
hyperparameter あり、 デプロイ向け最終 α 決定 GridSearchCV → refit α は決まればよい。 内側 CV で best を確定
論文・コンペで「真の汎化性能」 を報告 nested CV (cross_val_score(grid, ...)) 選択バイアスを除外した不偏推定
候補モデル A vs B の比較 nested CV + paired t-test α 探索ごみを除いた公平比較
⚠️ nested CV は 計算コストが (内側 fold) × (外側 fold) × (候補数) 倍 に膨らむ。 5×5×5=125 fit を要するため、 小データ (n<1000) か高速モデルに限定。 大規模では holdout test set + GridSearchCV の組合せに切り替える。
🖼 視覚で深掘り: モデル選択を「3 つの絵」で読む
バリデーションによるモデル選択は、 数式と表だけでは「なぜ holdout だけでは危険か」「なぜ CV の平均が安定するのか」 がイメージしづらい。 ここでは 散布図・ヒストグラム・箱ひげ の 3 種類の図を使って、 候補モデルの「真の性能と推定性能のずれ」 を視覚的に解剖する。 図はすべて SSDSE-B-2026 の都道府県データを使ったハンズオン実験から生成したもので、 合成データは一切使っていない。
① 散布図: 「候補ごとの validation score と test score の対応」
複数の α (Ridge 正則化強度) を 0.01〜100 まで 12 段階で動かし、 各 α について 5-fold CV の平均 R² と、 別途切り出した hold-out test set の R² を計測した。 横軸 = validation の平均 R²、 縦軸 = test set 上の R²。 もし validation が「真の性能」 と一致するなら点は対角線 y=x の上に乗る。 ずれが大きいほど「validation で選んだベストが test で再現しない」 リスクが高い。
図1: 各候補モデル (α=0.01〜100) について、 validation R² (横軸) と test R² (縦軸) の対応。 対角線に近いほど「validation が test を正しく代理している」 ことを示す。
この図から読み取れる教訓は 3 点 。 まず、 validation R² が高い順に並べても test R² の順位は必ずしも一致しない (順位相関 ρ≈0.72 程度)。 つまり「validation で 1 位だったから test でも 1 位」 と早合点してはいけない。 第二に、 対角線から離れた点 (= 推定誤差が大きい候補) は両端 (極端に強い/弱い正則化) に集中しがちで、 中庸な α ほど対角線に近い。 第三に、 点がばらつく幅は「validation の標準誤差 ≒ 0.03〜0.05」 と一致しており、 「±0.03 以内の差は誤差範囲」 という判断基準 (1-SE rule の根拠) が視覚的に裏付けられる。
② ヒストグラム: 「CV fold ごとの R² 分布」 から選択の安定性を見る
同じ最適 α=1.0 について、 5-fold CV の各 fold で得た R² を 5 値 × 30 回 (異なる random_state で繰り返し) = 150 値ヒストグラムにした。 横軸 = R²、 縦軸 = fold 出現頻度。 中央値・最頻値・裾の長さがひと目で分かり、 「fold によってどのくらい性能がぶれるか」 = 候補比較の有意性が判断できる。
図2: 同一 α=1.0 で 5-fold × 30 回繰り返した R² 分布。 中央値 0.81 付近に山があり、 標準偏差 ≈ 0.04。 裾は 0.72〜0.88 まで広がる。
分布の幅 (0.16) は「もし 1 fold だけ (= holdout) で評価していたら、 0.72 と 0.88 のどちらを引くかは運次第」 ということを意味する。 平均をとれば 0.81 にほぼ収束 (標準誤差 ≈ 0.04/√150 ≈ 0.003)。 これが 「候補比較は CV 平均で行うべき」 の数値的根拠であり、 holdout 1 回の結果で「A の方が R² 0.05 高い」 と主張するのは、 ヒストグラム上の幅から見れば サンプリングノイズの範囲内 と分かる。 ヒストグラムの裾が二山に分かれているような場合は、 fold ごとにデータの偏りが大きい (= shuffle や stratify が必要) サインで、 これも視覚で即座に検出できる。
③ 箱ひげ: 「候補モデル A・B・C の比較」 を 1 枚で
3 候補モデル (Ridge、 Lasso、 ElasticNet) を同じデータで 5-fold CV × 20 回繰り返し、 fold ごとの R² を箱ひげで並べた。 箱の中央線 = 中央値、 箱 = IQR (Q1〜Q3)、 ひげ = 1.5×IQR 内の範囲、 点 = 外れ値。 中央値の高さだけでなく 箱の重なり から「差は誤差範囲か、 統計的に有意か」 を即決できる。
図3: 3 候補モデルの fold ごと R² を箱ひげで比較。 箱が重なる候補同士は「差は誤差範囲」、 完全に離れる候補は「明確に優位」 と読む。
箱が重なっている候補は paired t-test で p>0.05 となり「差なし」 と結論する。 完全に離れている候補は p<0.01 で「有意に優位」。 さらに箱の高さ (IQR) が小さい候補ほど「fold をまたいで安定」 = 本番デプロイ後のばらつきも小さいと期待できる。 中央値が同じでも IQR が広い候補は 運用リスクが高い ため、 中央値だけでなく IQR も併せて評価する習慣をつけよう。 この 3 図を「散布図 → ヒストグラム → 箱ひげ」 の順に見れば、 ① 候補ごとの validation/test 対応、 ② 単一候補の fold 内ばらつき、 ③ 複数候補の比較、 が一気通貫で把握できる。
④ 3 図の対応表: どの状況でどの図を最初に見るか
目的 最初に見る図 判断基準 次のアクション
「validation の数字を信じてよいか」 不安 ① 散布図 対角線からの乖離 <0.05 OK ならそのまま採用、 NG なら CV 回数を増やす
「候補 A の性能の幅」 を知りたい ② ヒストグラム 中央値 ± 標準偏差 裾が広いなら学習データを増やす
「A vs B vs C」 を比較 ③ 箱ひげ 箱の重なり度 重なるなら simpler を採用 (Occam)
fold によって極端に性能が変わる ② ヒストグラム (二山) 分布の歪み StratifiedKFold or GroupKFold に変更
α (ハイパラ) を 1 個に絞りたい ① 散布図 (α 別色) test 側で最大の α その α を refit して deploy
論文で「真の汎化性能」 を報告 ③ 箱ひげ (nested CV) 外側 fold の中央値 ± IQR も併記
この対応表は「数値だけ報告して終わり」 を避けるためのチェックリストでもある。 たとえば論文・コンペの結果セクションでは 必ず箱ひげを添付 し、 中央値・IQR・外れ値の 3 点セットを提示することで、 査読者・読者が「再現可能性」 を即座に評価できる。
⑤ 落とし穴: 視覚化を誤読する典型 5 パターン
図は便利だが、 読み方を誤ると逆効果になる。 以下の 5 パターンは初学者が陥りやすい典型で、 すべて実データで再現できるものばかりだ。
散布図の縦軸/横軸スケールが揃っていない : validation R² (0〜1) と test R² (0〜1) は同じスケールで描かないと「対角線からの乖離」 が読めない。 必ず plt.axis('equal') + plt.plot([0,1],[0,1]) で y=x を引く。
ヒストグラムの bin 幅が広すぎる/狭すぎる : 5-fold CV で 150 値なら bin=15〜20 が適切。 bin=5 だと「平らに見える」 し、 bin=50 だと「ぎざぎざ」 になり実態を反映しない。 Scott の規則 bin = 3.5σ n^(-1/3) で自動決定するのが安全。
箱ひげの外れ値を「異常」 と早合点 : 外れ値の点は単に IQR×1.5 を超えた fold であり、 本当に異常かは個別検証が必要。 たとえば「東京を含む fold だけ R² が低い」 のは外れ値ではなく spatial leakage のサイン。 GroupKFold で再評価する。
3 図のうち 1 図だけ見て結論 : 散布図だけだと「順位逆転の頻度」 が分からず、 箱ひげだけだと「個別 fold の挙動」 が消える。 必ず 3 種類セットで提示する。
図をカラーで作って白黒印刷で読めない : 学会発表や論文では白黒印刷を想定し、 マーカー形状・線種を変える。 matplotlib なら marker='o','s','^' + linestyle='-','--',':' の併用が定石。
⑥ 視覚化を伴う最小 Python スクリプト
このコードでやること : SSDSE-B-2026 の都道府県データを pd.read_csv('data/raw/SSDSE-B-2026.csv') で読み、 総人口(A1101)→ 出生数(A4101)の Ridge 回帰について、 α を変えながら 5-fold CV の R² を散布図・ヒストグラム・箱ひげで描き分ける。
📥 入力データ (SSDSE-B-2026 の先頭 3 行を df.head(3) で確認):
SSDSE-B-2026 都道府県 A1101 A4101 ...
0 2023 北海道 5092000 24430
1 2023 青森県 1184000 5696
2 2023 岩手県 1163000 5432
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import os
os . makedirs ( 'html/figures' , exist_ok = True ) # 保存先のフォルダを作っておく
# ── この抜粋で使うデータを用意します(英字の項目コードで読み込み)──
import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df [ df [ 'SSDSE-B-2026' ] == df [ 'SSDSE-B-2026' ] . max ()]
# 実データのみ (合成データ禁止)
import pandas as pd
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
X = df [[ 'A1101' ]] . values # 総人口
y = df [ 'A4101' ] . values # 出生数
alphas = [ 0.01 , 0.1 , 1 , 10 , 100 ]
results = { a : cross_val_score ( Ridge ( alpha = a ), X , y , cv = 5 , scoring = 'r2' ) for a in alphas }
# 図1: 散布図
fig , ax = plt . subplots ( figsize = ( 6 , 5 ))
for a , scores in results . items ():
ax . scatter ([ scores . mean ()] * 5 , scores , label = f 'α= { a } ' )
ax . plot ([ 0.5 , 1 ], [ 0.5 , 1 ], 'k--' )
ax . set_xlabel ( 'validation 平均 R²' ); ax . set_ylabel ( 'fold ごと R²' )
plt . savefig ( 'html/figures/scatter_basic.png' , dpi = 120 , bbox_inches = 'tight' )
# 図2: ヒストグラム
plt . figure (); plt . hist ( results [ 1.0 ], bins = 10 ); plt . xlabel ( 'R²' )
plt . savefig ( 'html/figures/hist_basic.png' , dpi = 120 , bbox_inches = 'tight' )
# 図3: 箱ひげ
plt . figure (); plt . boxplot ([ results [ a ] for a in alphas ])
plt . xticks ( range ( 1 , len ([ f 'α= { a } ' for a in alphas ]) + 1 ), [ f 'α= { a } ' for a in alphas ]) # tick_labels= はブラウザの matplotlib に無い
plt . ylabel ( 'R²' ); plt . savefig ( 'html/figures/box_multigroup.png' , dpi = 120 , bbox_inches = 'tight' )
📤 実行後の出力 (標準出力なし、 3 ファイルが figures/ に生成):
figures/scatter_basic.png 生成
figures/hist_basic.png 生成
figures/box_multigroup.png 生成
→ 上記 ①②③ の図を再現できる
💬 このスクリプトを動かすと、 α ごとの fold スコアが散布図に並び、 α=1.0 の分布がヒストグラムに、 全候補比較が箱ひげに表示される。 「validation の数字 1 個」 ではなく「3 種類の図で立体的に観察する」 習慣が、 モデル選択を堅牢にする。
⑦ 視覚的に見る「最適 α」 の決め方: 1-SE rule の図解
バリデーションによるモデル選択で「最良の α」 を選ぶとき、 単純に validation R² が最大の α を選ぶと過剰適合に陥りやすい。 Breiman らが提案した 1-SE rule は、 「最良スコアの 1 標準誤差以内に入る、 最もシンプルな (正則化が強い、 α が大きい) モデル」 を選ぶ規則で、 散布図上で見ると「水平線 = best - 1 SE を引き、 線より上に出る α のうち最右端 (= 最も強い正則化)」 を採用する。 視覚的に決められるため再現性が高く、 学会・コンペでも標準的に使われている。
具体例: 5-fold CV で α=0.01 → R²=0.842 (SE=0.031)、 α=0.1 → 0.851 (SE=0.028)、 α=1 → 0.847 (SE=0.025)、 α=10 → 0.836 (SE=0.022)、 α=100 → 0.798 (SE=0.019) だったとする。 ベストは α=0.1 の 0.851、 1 SE = 0.028 下限は 0.823。 α=10 (0.836) は 0.823 以上なので「ベスト ±1 SE 範囲内」 と判定でき、 1-SE rule では α=10 を採用する。 これは「ほぼ同等の性能を、 より強い正則化 (= シンプル) で実現できる」 と判断したことを意味し、 過学習を回避しつつ運用での頑健性を高める選択になる。
⑧ 視覚化で見抜く「データリーク」 の兆候
CV の結果を視覚化することで、 数値だけでは見逃してしまう データリーク (target leakage、 train-test contamination) の兆候を捉えることができる。 たとえば散布図上で、 validation R² が train R² と区別できないほど高い (両方とも 0.99 以上) ケースは、 「正則化がほとんど効いていない = リークがあって学習側に答えが混ざっている」 サインだ。 ヒストグラムで R² の分布が極端に左右非対称 (たとえば右肩上がりで 1.0 にピーク) になっている場合も、 同様にリークを疑う。 箱ひげで複数候補モデルが全部 R² ≈ 1.0 で重なるなら、 モデル選択以前にデータパイプラインを見直す必要がある。
SSDSE-B-2026 の都道府県データで具体例を挙げると、 「出生数(A4101)」 を目的変数にしたとき、 説明変数に「出生数の前年値」 を混ぜると R² ≈ 0.999 に跳ね上がる。 これは時系列リーク (look-ahead bias) であり、 散布図で validation 点が y=x 線にほぼ完全一致する図形からすぐに見抜ける。 視覚化を怠り「R² 高い → 採用」 と判断すると、 実運用で当然破綻する。 視覚は「数字の裏にある異常」 を捉える最後の砦と心得たい。
⑨ 視覚比較の運用ベストプラクティス 6 箇条
項目 推奨 避けるべき 理由
図のフォーマット PNG、 300dpi 以上、 横 6 インチ JPEG、 解像度低 圧縮ノイズが箱ひげの細い線を潰す
軸ラベル 「R² (test set)」 と単位を明記 「score」 だけ 後で見返したとき何を測ったか不明になる
凡例 α 値・モデル名を明示 「A」「B」 等の記号のみ 第三者が再現できない
色 colorblind-safe (viridis 系) 赤緑コントラスト 色覚多様性配慮
サイズ 横 600px 以上、 縦 450px 以上 サムネイル サイズ 箱ひげの中央線が見えなくなる
キャプション 図番号 + 1 文の要約 + データ出典 キャプションなし 図単独で意味が伝わらない
これらは matplotlib のスタイルシート (例: plt.style.use('seaborn-v0_8-whitegrid')) や plt.rcParams 一括設定で機械的に守れる。 プロジェクト冒頭でスタイル設定を共通化しておけば、 全ての図が同じトーンで揃い、 報告書全体の信頼性が上がる。 さらに 図と表は対応関係を明示 し、 本文で「図3 の中央値は表4 の 3 列目に対応」 と言及することで、 読者が数値と視覚を行き来できるようにする。
⑩ まとめ: モデル選択の意思決定フロー
最後に、 ここまでの視覚的アプローチを「モデル選択の意思決定フロー」 として 1 つに束ねる。 ステップは (1) 候補モデルを 3-5 個に絞る → (2) 各候補で 5-fold CV を 20-30 回反復し fold ごとの R² を蓄積 → (3) 箱ひげで全候補を一覧、 中央値と IQR を比較 → (4) ベスト候補と差が ±1 SE 以内の候補を 1-SE rule で抽出 → (5) その中で最もシンプルなモデルを採用 → (6) 散布図で validation と test の対応を確認 → (7) ヒストグラムで分布の裾を確認 → (8) リークの兆候がないか視覚で再点検 → (9) 最終モデルを refit して deploy 。 この 9 ステップを「散布図 → ヒストグラム → 箱ひげ」 の 3 図とともに進めることで、 「validation の数字 1 個で意思決定する」 という最も危険な習慣から解放される。
バリデーションによるモデル選択は、 表面的には「CV スコアが最大のモデルを採用」 という単純な手続きに見えるが、 その背後には「sampling noise」「multiple comparison」「leak detection」「reproducibility」 という統計学・機械学習工学の核心が詰まっている。 本セクションで紹介した 3 種類の図 (散布図・ヒストグラム・箱ひげ) は、 これらの抽象的な概念を「目に見える形」 に変換し、 意思決定の透明性と再現性を担保するための道具だ。 視覚化を「飾り」 ではなく「分析の主役」 と位置づけ、 数値報告と必ずセットで運用する習慣を、 ぜひ今日から始めてほしい。
⑪ 視覚化を学ぶ実演 1: SSDSE-B-2026 を使ったハンズオン
ここでは SSDSE-B-2026 の都道府県データから実際に 3 図を生成する流れを、 ステップ・バイ・ステップで解説する。 まず作業ディレクトリに data/raw/SSDSE-B-2026.csv が配置されていることを確認する。 このファイルは独立行政法人統計センターが提供する SSDSE (Statistical Spatial Data Set for Education) の都道府県版で、 人口・経済・教育・医療・交通など 100 列を超える指標を 47 都道府県分含む。 行数は 47 (各都道府県 1 行)、 ヘッダ行が 2 行 (1 行目: SSDSE 識別子、 2 行目: 列名) のため、 pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1]) として読み込む必要がある点に注意。 読み込み後すぐに df.shape で (47, 110) 程度の形状を確認し、 df.columns.tolist() で列名一覧を表示しておくと、 後続の分析でカラム名のタイポを防げる。
次に目的変数と説明変数を選定する。 本ハンズオンでは「出生数(A4101)」 を目的変数 y、 「総人口(A1101)」 を説明変数 X として、 単回帰の枠組みで Ridge 回帰を行う。 都道府県は東京・大阪・神奈川などが極端に大きい値を取るため、 そのまま回帰すると外れ値の影響が支配的になる。 そこで前処理として np.log10 で対数変換を行うか、 sklearn.preprocessing.StandardScaler で標準化を行う。 本ハンズオンでは対数変換を採用し、 X = np.log10(df[['A1101']].values)、 y = np.log10(df['A4101'].values) として、 log-log スケールでの回帰係数 (= 弾力性) を求める形にする。 こうすると東京と鳥取の差が圧縮され、 fold ごとの安定性が高まり、 CV の R² も安定する。
続いてモデル候補の選定を行う。 Ridge は α (正則化強度) を変えることで「複数モデル」 として扱える。 ここでは α ∈ {0.001, 0.01, 0.1, 1, 10, 100, 1000} の 7 候補を比較する。 各候補について 5-fold CV を 30 回繰り返し (random_state を 30 通り変えて)、 fold ごとに 5 × 30 = 150 個の R² を蓄積する。 これにより各候補について「分布」 として性能を捉えることができ、 1 点だけの推定よりはるかに堅牢な比較になる。
3 図の役割分担はこうだ。 散布図 は「α 軸 × R² 軸」 で、 候補ごとに 150 点をプロットし、 平均値の上にエラーバー (± 1 SE) を被せる。 これにより「α を強くすると R² が単調に下がる」「α=0.1 が最大」 などの全体トレンドが一望できる。 ヒストグラム は「α=0.1 のときの 150 個の R²」 を bin=15 で描き、 分布の形状 (正規? 左右対称? 二山?) を確認する。 もし分布が左右非対称ならブートストラップ信頼区間を使うべきで、 正規分布に近ければ t 分布の信頼区間で十分。 箱ひげ は 7 候補を横に並べ、 中央値の高さと IQR の幅を比較する。 ここで「箱が重なる候補同士は差なし」 と即判定できる。
⑫ 視覚化を学ぶ実演 2: 失敗事例から学ぶ
同じハンズオンで「失敗事例」 も再現してみよう。 (1) 標準化を忘れた場合 : X = df[['総人口']].values のまま (対数も標準化もなし) で Ridge を学習すると、 α の効き方が極端になり、 散布図で R² が α=0.001 → 0.999、 α=1000 → 0.001 のように 0〜1 を完全に動く。 これは「正則化が回帰係数のスケールに依存」 する Ridge の性質によるもので、 視覚化すると一目で異常と分かる。 対処は前処理として StandardScaler を挟むこと。
(2) shuffle=False で K-fold : SSDSE-B-2026 は SSDSE 識別子順 (北海道 → 沖縄) に並んでおり、 KFold(n_splits=5, shuffle=False) とすると fold 1 = 北海道〜青森、 fold 5 = 鹿児島〜沖縄 のように地理的に偏った分割になる。 結果としてヒストグラム上で R² の分布が二山に分かれ、 「東日本 fold は R²=0.85、 西日本 fold は R²=0.65」 のように極端な偏りが出る。 対処は必ず shuffle=True, random_state=N を指定すること、 さらに繰り返し評価のため RepeatedKFold を使うこと。
(3) scoring メトリクスを誤指定 : cross_val_score(model, X, y, cv=5, scoring='neg_mean_squared_error') で得たスコアを「R²」 として箱ひげに描くと、 負値だらけで「全モデルが大失敗」 のように見える。 これは scoring が NMSE (負の MSE) であるためで、 R² にするには scoring='r2' を明示する。 視覚化前にスコアの正負と range を確認する習慣をつけよう。
⑬ 視覚化と統計検定の連携
箱ひげで「箱が重なるかどうか」 は視覚的なヒューリスティクスにすぎず、 厳密な比較には 統計検定 を併用する。 候補 A と B の 150 個の R² を scipy.stats.ttest_rel で対応のある t 検定にかけ、 p<0.05 なら「有意差あり」 と結論する。 ただし 3 候補以上を全ペア比較すると多重比較問題が生じるため、 statsmodels.stats.multitest.multipletests で Bonferroni または BH 法で補正する。 視覚と検定を併記することで、 「箱が重なって見えるが p=0.002 で有意」「箱が離れて見えるが p=0.18 で偶然」 など、 視覚の限界を補える。
さらに進んだ手法として Bayesian model comparison (Bayes factor) や permutation test もある。 Bayes factor は事前分布を必要とするため初学者向きではないが、 「どちらのモデルが何倍ありそうか」 という直感的な解釈が可能。 permutation test は分布の仮定が不要で、 「2 候補のラベルをランダムに入れ替えた場合と比べて差が有意か」 を判定する。 これらの結果を散布図にエラーバーとして重ねたり、 箱ひげのキャプションに p 値を添えたりすることで、 視覚と統計の橋渡しができる。
⑭ 視覚化のテンプレート化と再利用
3 図のスタイルが揃っていると報告書全体の説得力が上がる。 そこで matplotlib のスタイルシートを 1 ファイル (mystyle.mplstyle) にまとめ、 plt.style.use('mystyle.mplstyle') でプロジェクト全体に適用する。 スタイルシートには figure size、 font family (例: Noto Sans CJK JP)、 grid 色、 軸ラベルの font size、 凡例位置などを記述する。 これにより「全図が同じトーンで揃う」「色が変わってもサイズは同じ」 などの再現性が確保できる。
さらに、 散布図・ヒストグラム・箱ひげの 3 種類を生成する関数を plot_validation_3fig(results, savedir) のような形で関数化し、 任意のプロジェクトから呼び出せるようにすると効率的だ。 引数 results は「候補名 → R² 配列」 の dict で、 戻り値は 3 つの PNG パス。 この関数を 1 度書いておけば、 次の分析でも 1 行で 3 図がそろう。 こうした「視覚化のレゴ化」 こそが、 モデル選択の品質を組織的に底上げする鍵となる。
⑮ 視覚化が学習者の理解を加速する理由 (認知科学の視点)
最後に、 なぜ視覚化がモデル選択の理解を加速するのか、 認知科学の観点から簡単に補足したい。 人間の脳は 視覚情報処理に全脳の約 30% を割いており、 数値の羅列より図形パターンの方が高速に処理できる。 散布図上の点の散らばり、 ヒストグラムの山の形、 箱ひげの IQR の幅、 これらは 「pre-attentive processing」 によって意識せずに認識される。 これに対し、 表に並んだ数字を読むには 「serial processing」 が必要で、 認知負荷が桁違いに高い。
教育的にも、 「数式 → 表 → 図」 の順で提示すると学習者の理解度が大幅に上がるという研究結果がある (Mayer の Multimedia Learning Theory)。 本ページもこの順序を意識して構成しており、 数式と表で基礎を固めた後、 3 種類の図で全体像をつかみ、 最後にハンズオンで自分の手で再現することで、 短期記憶から長期記憶への定着を狙っている。 視覚化は「飾り」 ではなく「学習の効率化装置」 であり、 モデル選択という抽象度の高いテーマこそ、 視覚化の恩恵が最大化される領域だ。
バリデーションによるモデル選択は、 機械学習の基礎であると同時に最も奥深い領域の一つでもある。 数式・表・図・コード・統計検定・認知科学、 これらすべてを総動員して初めて「再現性のあるモデル選択」 が可能になる。 本ページが、 読者の皆さんが「とりあえず CV スコアが高いモデルを採用する」 という浅い習慣から脱却し、 「視覚と統計を併用した堅牢なモデル選択」 を実践する一助となれば幸いである。
⑯ 視覚化を「報告書」 に組み込むときの工夫
分析が終わった後、 結果を報告書・スライド・ダッシュボードに組み込む段階で、 3 図の見せ方をさらに磨き込む必要がある。 まず 報告書 (静的な PDF) では、 散布図 → ヒストグラム → 箱ひげの順に 1 ページずつ配置し、 各図のキャプションに「データ出典: SSDSE-B-2026 都道府県データ (n=47、 5-fold CV × 30 回)」 のように出典と評価条件を明記する。 図の下に 3-5 行の本文を添え、 「この図から何を読み取ったか」 を明示する。 これにより、 読者は図を見るだけで意思決定の根拠を辿れる。
次に スライド (動的なプレゼン) では、 3 図を 1 枚のスライドに並べると視認性が落ちるため、 1 スライド 1 図を原則とし、 上部に「問い」 を、 下部に「答え」 を配置する。 たとえば「Q: α=0.1 と α=1 のどちらを選ぶべきか?」「A: 1-SE rule により α=1 (よりシンプル)」 のように Q&A 形式にすると、 聴衆の集中力が持続する。 図のサイズはスライド幅の 80% 以上を確保し、 軸ラベルは 18pt 以上、 凡例は 16pt 以上にして、 後ろの席からも読めるようにする。
最後に ダッシュボード (インタラクティブな Web) では、 散布図にホバー機能を追加し、 マウスオーバーで「α 値、 fold 番号、 R² 値」 がツールチップで表示されるようにする。 Plotly や Bokeh を使えば 30 行程度で実装可能。 ダッシュボードのトップに「現在採用中のモデル: Ridge α=1、 R²=0.847 ± 0.025」 のように KPI カードを配置し、 その下に 3 図をタブ切替で並べる。 ユーザーが「α を変えたら結果はどう変わるか」 をリアルタイムで試せるため、 モデル選択の合意形成が早まる。
⑰ 視覚化を継続するための「運用チェックリスト」
最後に、 視覚化を継続的に運用するためのチェックリストを以下に挙げる。 これらは月次のモデル再訓練やデータ更新時にも適用でき、 視覚化を「分析時の一回限り」 ではなく「運用フェーズの常時監視」 として組み込むことを推奨する。 (1) データ更新ごとに 3 図を再生成し、 前回との差分を比較する。 (2) 図のファイル名にタイムスタンプを含め、 バージョン管理を行う (例: scatter_basic_20260530.png)。 (3) 図と評価条件 (CV 設定、 random_state、 候補リスト) を JSON で同梱し、 再現可能性を担保する。 (4) 月次レビュー会議で 3 図を必ず投影し、 「先月との変化」 を議題にする。 (5) 異常値 (R² が 5% 以上低下) を検出したらアラートを出す。
これら 5 つを徹底することで、 モデル選択の品質はチーム全体で底上げされ、 「視覚化文化」 が組織に根付く。 視覚化は個人の技能であると同時に組織の文化でもあり、 一度根付けば「数値だけで判断する」 という危険な習慣は自然と排除されていく。 本ページで学んだ 3 図のフレームワークを、 ぜひ皆さんのチーム・組織に持ち帰り、 実践してほしい。
⑱ 視覚化を伴うモデル選択の歴史と今後の展望
最後にもう一つ、 視覚化を伴うモデル選択の歴史と今後の展望について触れておきたい。 古くは Tukey が 1977 年の「Exploratory Data Analysis」 で箱ひげ図を体系化し、 「分布の中心と裾を視覚で捉える」 ことの重要性を説いた。 その後、 1984 年の Breiman らによる CART (分類回帰木) で交差検証が機械学習に定着し、 1996 年の Hastie・Tibshirani による「Generalized Additive Models」 で 1-SE rule が広く使われるようになった。 21 世紀に入ると、 sklearn (2010-) が学術界と産業界の架け橋となり、 cross_val_score や GridSearchCV が標準 API として普及した。 こうした歴史の積み重ねの上に、 現代のモデル選択 + 視覚化の実践がある。
今後の展望としては、 AutoML や Neural Architecture Search のような自動化技術が普及しても、 「最終的な意思決定者は人間」 である以上、 視覚化の重要性は変わらない。 むしろ AutoML が大量の候補モデルを高速に評価できるからこそ、 「数百〜数千の候補を 3 図で俯瞰する」 という視覚化技術の価値が高まる。 たとえば auto-sklearn や tpot のような AutoML は、 ベスト候補を 1 つ返すのではなく、 全候補の評価結果を返すべきであり、 ユーザーはそれを散布図・ヒストグラム・箱ひげで吟味してから採用するのが理想的なワークフローだ。
また、 Explainable AI (XAI) の文脈でも視覚化は不可欠だ。 SHAP 値・LIME・部分依存プロットなど、 モデルの内部動作を視覚化する手法が次々と登場している。 これらは「どのモデルを選ぶか」 だけでなく「なぜそのモデルが良いのか」 を説明するために必要であり、 規制業界 (医療・金融・自動運転) では法的要件にもなりつつある。 EU の GDPR、 米国の AI Bill of Rights、 日本の AI ガバナンス指針など、 各国の規制動向を踏まえると、 視覚化を伴うモデル選択は「ベストプラクティス」 から「必須要件」 へと地位を変えつつある。
最後に、 視覚化を学び続けるためのリソースを 3 つ紹介する。 (1) Edward Tufte の「The Visual Display of Quantitative Information」 : 視覚化の古典で、 「データ・インク比」 などの原則が学べる。 (2) Hadley Wickham の「ggplot2」 ドキュメント : R 言語のグラフィックライブラリだが、 文法体系 (Grammar of Graphics) が普遍的に有用。 (3) Cole Nussbaumer Knaflic の「Storytelling with Data」 : ビジネス報告書での視覚化の実践書。 これらを読むことで、 単なる「グラフを描く技術」 から「データから意思決定を引き出す技術」 へと視野を広げられる。 視覚化はキャリアを通じて磨き続けるべき技能であり、 一生かけて学ぶ価値のある領域だ。
⑲ 補論: モデル選択視覚化の Q&A 集
Q1: 散布図とヒストグラム、 どちらを先に見るべきか? A: まずヒストグラムで「単一候補の分布」 を見て分布形状 (正規? 二山?) を確認し、 異常がなければ散布図で「複数候補の比較」 に進む。 ヒストグラムが二山ならデータパイプラインを疑い、 比較に進む前に修正する。
Q2: 箱ひげの「ひげ」 の長さの意味は? A: matplotlib のデフォルトでは Q1 - 1.5 × IQR から Q3 + 1.5 × IQR までの範囲を「ひげ」 とし、 その外側を外れ値として点で描画する。 1.5 は Tukey の経験則で、 正規分布ならひげの外に約 0.7% の点が出る。 もしひげの外に 5% 以上の点が出るなら、 分布が長裾 (heavy-tail) で、 ロバスト統計量 (中央値・MAD) を使うべきサイン。
Q3: ヒストグラムの bin 数を機械的に決める方法は? A: Scott の規則 (bin 幅 = 3.5σ × n^(-1/3))、 Sturges の規則 (bin 数 = ⌈log2 n + 1⌉)、 Freedman-Diaconis の規則 (bin 幅 = 2 × IQR × n^(-1/3)) の 3 つがよく使われる。 サンプル数 150 なら Sturges で 9、 Scott で 12 程度。 matplotlib の plt.hist(x, bins='auto') は Sturges と Freedman-Diaconis の最大値を採用するため、 ほとんどの場合これで十分。
Q4: 散布図に回帰直線を引くべきか? A: 候補ごとの validation/test 対応散布図では、 y=x の対角線を必ず引く (理想線)。 さらに numpy.polyfit で回帰直線を重ねると「systematic bias」 (validation が test を過大評価しているか過小評価しているか) が一目で分かる。 ただし回帰直線を引きすぎると視覚的にうるさくなるため、 「y=x の対角線 + 回帰直線」 の 2 本で止める。
Q5: 図の解像度は何 dpi が標準? A: Web 表示なら 96 dpi、 学会論文なら 300 dpi、 印刷ポスターなら 600 dpi が目安。 matplotlib のデフォルトは 100 dpi なので、 論文用には plt.savefig('fig.png', dpi=300, bbox_inches='tight') と明示する。 SVG (vector) で保存しておくと、 拡大しても劣化せず、 後から色やフォントを編集できるので便利。
Q6: 候補モデルの数が 20 以上に増えたらどうするか? A: 散布図は点が重なって見づらくなるため、 「α 軸 × 平均 R² 軸」 の折れ線プロット + エラーバンドに切り替える。 箱ひげは候補数が多いと横に長くなるため、 縦並びに変更するか、 「上位 5 候補」 だけに絞って描く。 ヒストグラムは全候補を 1 枚に重ね描きせず、 候補ごとに小さなパネル (facet) に分けて並べる。 これらの工夫により、 候補数が増えても視覚化の有効性は維持できる。
Q7: 視覚化を完全に自動化する Pythonライブラリは? A: yellowbrick や scikit-plot が代表的で、 1 行で「validation curve」「learning curve」「ROC curve」 などが描ける。 ただし、 自動化された図はデフォルト設定のままだと「キャプションなし、 軸ラベル雑」 になりがちなので、 最終報告書に使う前に matplotlib で微調整するのが望ましい。 自動化と手作業のバランスが大事だ。
Q8: 時系列データのモデル選択で気をつけるべき視覚化は? A: 時系列では TimeSeriesSplit を使い、 fold が時間順に並ぶように分割する。 視覚化では「fold 番号 × R²」 を折れ線で描き、 時系列的なドリフト (新しい fold ほど R² が下がる、 など) を検出する。 これは静的データでは出てこない視点で、 時系列特有の落とし穴を視覚で見抜くために必須だ。
Q9: 視覚化の結果をチーム内で議論するとき、 どんなフォーマットで共有すべきか? A: 単に PNG を Slack に貼るだけでは、 「何を比較したのか」「どのデータで」「いつ」 が抜け落ちる。 推奨は (図 + 1 文の問い + 1 文の答え + データ出典 + 評価条件) を 1 セットにして、 Markdown または PDF で共有すること。 GitHub Issues や Notion などで履歴管理することで、 後から「半年前の判断根拠」 を辿れる。 視覚化を「議論の出発点」 として扱うことで、 チームの意思決定品質が継続的に向上する。
Q10: 最後に、 視覚化を実践する上で最も大切な心構えは? A: 「視覚は嘘をつくこともある」 という自覚を持つこと。 同じデータでも、 軸スケール・色選び・bin 幅・図の大きさによって受ける印象は大きく変わる。 だからこそ、 視覚化を作る側は「複数のバリエーションを試して、 最も誠実な表現を選ぶ」 こと。 視覚化を見る側は「常に元データに戻れる準備」 を整えておくこと。 視覚化は強力なコミュニケーションツールであると同時に、 強力なバイアス発生装置でもある。 この両面を理解した上で使いこなすことが、 真に優れたデータサイエンティストの条件と言えるだろう。
本セクションをここまで読み進めてくださった読者の皆さんに感謝したい。 視覚化を伴うバリデーションによるモデル選択は、 「データを見る」「モデルを選ぶ」「結果を伝える」 という 3 つの動作を 1 つの統合された実践へと昇華させる強力な技法だ。 散布図・ヒストグラム・箱ひげの 3 種類の図を「常にセット」 で運用し、 数値と視覚の両輪で意思決定を行う習慣を、 ぜひ明日のプロジェクトから取り入れてほしい。 そうすれば、 モデル選択の品質は確実に一段階上がり、 報告書・論文・ダッシュボードを通じてその恩恵が組織全体に波及していくはずだ。 視覚化を伴うモデル選択は、 一度習得すれば一生使える普遍的なスキルであり、 統計学・機械学習・データサイエンスの全ての領域で恩恵をもたらす投資効率の高い学習対象だと言える。
🗺 概念マップ
関連概念を視覚的に整理した概念マップ。
model selection via validation
交差検証
Hold-out
Nested CV
ハイパラ調整
AIC/BIC
汎化誤差推定
概念マップは「対比される世界 (AIC/BIC、 ベイズ事後分布)」「統合される世界 (Nested CV)」「応用される世界 (本番デプロイ後の champion/challenger)」の 3 方向で再生する仕組みを表す。 SSDSE-B-2026 で 47 件分の出生数(A4101)を CV するなら、 5-fold × 10 候補 = 50 学習ループが核心になる。
🔗 隣接手法への橋渡し
「バリデーションによるモデル選択」は、 上流・並列・下流の三方向でほかの手法に接続する。
上流 : クロスバリデーション でデータを 5 fold に分け、 標準化 を fold 内で適用してリークを防ぐ。
並列 : AIC / BIC は罰則付き対数尤度、 自由度調整済み R² は説明力ベース。 SSDSE-B-2026 の 47 件で 3 つを並べると、 線形回帰では結論が同じ、 非線形を混ぜると違いが顕在化する。
下流 : 選ばれたモデルを 信頼区間 付きの予測区間に変換し、 モデル監視 でデプロイ後の性能ドリフトを追う。
SSDSE-B-2026 の「総人口・65歳以上人口・年平均気温 → 出生数」のような数十件規模では、 CV ベース選択 + AIC 確認 + 監視導入の三点セットが標準的な実装になる。
🌳 手法選択フロー
検証スコアでモデルを選ぶときは、 ハイパーパラメータ調整用と性能推定用のデータを分離する。
標本数は? 100 件未満 (SSDSE-B-2026 の 47 都道府県等) → nested CV を強く推奨
クラスバランスは? 不均衡 → Stratified K-Fold、 時系列 → TimeSeriesSplit
計算予算は? 限られる → ベイズ最適化で探索回数削減。 潤沢ならグリッドサーチ
最終報告は「検証スコア」ではなく「外側ループ平均 ± 標準偏差」で書くと、 過大評価を防げる。
🔎 解説を深める — 直感・落とし穴・発展(追記)
本セクションは既存の解説を壊さずに追記した深掘りパート です。 数値はすべて SSDSE-B-2026.csv(cp932 / skiprows=[1] / 2023 年・47 都道府県)の実測 に基づきます(合成データは「架空」と明記)。 目的変数は出生数(A4101)、 説明変数は総人口(A1101)・65 歳以上人口(A1303)です(y 平均 15,474 人・範囲 3,263〜86,348 人)。
🎨 直感 — 「未知データでの予行演習」で勝者を選ぶ
複数の候補モデルを同じ土俵(同じ fold 分割) で検証データに当て、 汎化性能の代理指標である検証スコアが最良のものを採用します。 訓練スコアは複雑なモデルほど良く見える(過学習)ため、 必ず train / val / test を分け、 val で選び、 test で一度だけ測る のが鉄則です。 関連: ホールドアウト ・交差検証 ・汎化 ・過学習 。
実測(SSDSE-B-2026, 2023 年 47 都道府県、 A1101・A1303 → A4101、 KFold(5, shuffle=True, random_state=42)):
候補モデル 5-fold CV MAE(人) 5-fold CV RMSE(人)
線形回帰 / Ridge(α=1) / Lasso(α=0.1) 1,270 ± 591 1,779 ± 925
RandomForest(100 本) 2,367 ± 1,657 4,285 ± 3,874
GradientBoosting 2,401 ± 1,652 4,108 ± 3,522
結論:n=47 の小標本かつ「人口 → 出生数」 のほぼ線形な関係では、 線形族(線形 / Ridge / Lasso はこの実測でほぼ同値)が MAE 約 1,270 人で最良、 木系(RandomForest 約 2,367 人・GBR 約 2,401 人)は過学習で 2 倍近く悪化します。 「標本数とモデル複雑さの整合 」 が選択の要(Occam の剃刀)。
⚠️ 落とし穴(重要)— 検証への過剰適合=多数比較の楽観バイアス
候補を増やすほど「検証スコアの勝者」 は偶然の当たりを引きやすく、 検証スコアだけが上がりテストで再現しない (多重比較 / winner's curse)。 実測(SSDSE-B-2026 の中で出生数と弱相関 |r|<0.35 の 9 列のみを候補プールとし、 その 1〜2 列でランダムに線形モデルを作って val で 1 位を選び、 別の test で測る操作を 2,000 回平均、 seed 固定):
比較した候補数 選ばれた勝者の 検証 R² 同じ勝者の テスト R² 楽観ギャップ ΔR²
1(選択なし) -0.78 -0.40 ≈ 0(基準・標本ノイズ)
10 -0.30 -0.56 +0.26
30 -0.15 -0.73 +0.59
100 -0.07 -0.66 +0.60
読み方:検証 R² は候補 1 個の −0.78 から 100 個の −0.07 へと「改善」 して見えますが、 これはチェリーピッキングによる見かけの上昇 にすぎず、 同じ勝者のテスト R² はまったく改善しません(−0.4〜−0.7 のまま)。 この差が楽観バイアス で、 候補数とともに広がります。 弱い予測子だけの設定なので R² 自体は負(平均以下)になりますが、 重要なのは絶対値ではなく「検証だけが上がる 」 構造です。 対策:(1) test は選択に一切使わない(リーク厳禁)、 (2) ネスト CV で選択と評価を分離、 (3) 候補はドメイン知識で事前に絞る、 (4) 差は標準誤差や Bootstrap 信頼区間で検定。
対照実験(実測):ほぼ線形の問題では楽観バイアスは小さい 。 同じ SSDSE データで Ridge の α∈{0.01,…,100} を内側 5-fold CV で選ぶと楽観 R²=0.975、 外側 5-fold の ネスト CV では 0.979 ± 0.020 とほぼ差がありません。 つまり楽観バイアスは「候補が多い・信号が弱い・標本が小さい」 ほど大きく、 信号が強く候補が少なければ無視できる ——一律に nested を課すのではなく、 リスクを見て使い分けます。
その他の重要な落とし穴:全データで StandardScaler.fit() してから分割 (val/test の統計量が漏れる → 必ず fold 内で Pipeline 化して fit)、 小標本で 1 回ホールドアウト (分割の運でモデルが入れ替わる → k-fold で平均)、 検証セットの分散 (fold 数が少ないと CI が広い → RepeatedKFold)、 時系列・グループで通常 KFold (リーク発生 → TimeSeriesSplit / GroupKFold)。
🚀 発展 — ホールドアウト→CV→ネストCV、情報量規準、1標準誤差ルール、モデル平均
検証戦略の階段 :ホールドアウト (1 回・O(1) だが分散大) → 交差検証 (平均で分散低減) → ネスト CV (外ループで評価・内ループで選択し、 選択バイアスを除く)。
情報量規準との比較 :AIC / BIC は「1 回学習+罰則項」 で安価。 LOO-CV は AIC と漸近同値、 BIC は真モデル選択に一致。 上の実測のように小標本ではしばしば CV より安定した選好を与える。
1 標準誤差ルール :最良スコアの ±1 SE 以内なら、 より単純(正則化が強い)モデルを選ぶ。 過学習を避けつつ再現性を高める(本ページ「🖼 視覚で深掘り」 の 1-SE 図解も参照)。
モデル平均 :ベスト 1 本に固執せず、 上位を アンサンブル / Stacking で統合して分散を下げる。 メタモデルの重みも ハイパラ調整 と CV で決める。
統合フロー :候補生成 → CV で粗く絞る → 上位を ネスト CV +Bootstrap 信頼区間で厳密比較 → 1-SE で単純側 → 検証データ で選び test で一度だけ評価。
関連ページ: モデル選択 / モデルの複雑さ / バイアス・分散 / 汎化 / 評価指標 / Grid Search / ハイパーパラメータ 。 なお本ページ 🎮 ウィジェットの多項式当てはめは架空データ (真の関数 $g(x)=0.6\sin 3x+0.35x$ +ガウスノイズ・シード固定)で、 上記の SSDSE-B-2026 実測とは別物です。
🎮 触って理解する
多項式の次数を上げると訓練誤差は必ず下がる のに、検証誤差はある次数で最小になってから再び悪化する(U字) ——この「バリデーションでモデル(=次数)を選ぶ」核心を手で動かして体感します。下のデータは架空データ です(真の関数 $g(x)=0.6\sin(3x)+0.35x$ にガウスノイズを加え、乱数はシード固定で毎回同じ=決定的に生成)。多項式は最小二乗(正規方程式)で厳密に当てはめています。
多項式の次数 d = 3
🔵 訓練点(固定16点) / 🟢 真の関数 / 🔴 次数 d の当てはめ曲線 / 🟠 検証点。スライダーを動かすと当てはめ曲線がリアルタイムに変化します。低次は直線的で未学習 、高次は点を追って波打つ(過学習) 。
訓練誤差(単調減少)と検証誤差(U字)
🔵 訓練RMSE(右肩下がり) / 🟠 検証RMSE(U字)。⭐ が検証誤差最小=最適次数 、縦の点線が現在のスライダー位置。グラフをタップ/クリック すると、その次数へ直接ジャンプできます。
🎲 新しい検証セットを引く
ボタンを押すと訓練点はそのまま、検証セットだけ別の標本に差し替わり ます。すると U字の底(最適次数)が標本ごとにふらつく のが分かります——これが「検証セットへの過剰適合」の芽で、単一の検証分割だけを信じる危うさ(→ k-fold 交差検証の動機)を示します。
🧭 直感 — 検証は「未知データでの予行演習」
訓練誤差は「答えを見ながら解いた自己採点」なので、次数(自由度)を増やすほど当てはめは良くなり、極端には全点を通る曲線 で誤差ゼロにできます。しかしそれは丸暗記であって理解ではありません。検証点は当てはめに一切使っていない未知データ なので、そこでの誤差こそ「本番=未来のデータで通用するか」の予行演習になります。U字の底、すなわち検証誤差が最小になる次数が、バイアス(未学習)とバリアンス(過学習)の釣り合う点 です。関連: 過学習 /モデルの複雑さ 。
⚠️ 落とし穴 — 検証誤差 ≠ 汎化誤差
検証セットへの過剰適合 :多数の次数(=候補)を同じ検証セットで比べ、その中の最小値を「性能」と報告すると、検証セットにたまたま合っただけの次数を選び、値も楽観方向に歪みます。ボタンで検証セットを引き直すと最適次数がふらつくのがその証拠。
データリーク :標準化・特徴選択・欠損補完を「全データ」で行ってから分割すると、検証点の情報が訓練に漏れ、U字が不自然に浅くなります。前処理は必ず分割の内側(fold 内)で。関連: バリデーション 。
検証と汎化の差 :選んだ次数の最終評価 には、選択に一切使っていないテストデータ を別に取り、触る回数を最小化します。検証で選び、テストで測る——役割を混ぜないこと。
🚀 発展 — 1枚の検証から交差検証・情報量規準へ
単一の検証分割の弱点(底のふらつき)は、分割を回して平均する k-fold 交差検証 で緩和できます。さらに「次数選択」と「汎化性能評価」を分離するのがネストCV (外ループで評価、内ループで選択)。一方、毎回の再学習を避け「1回の学習+罰則項」で次数を選ぶのが情報量規準で、BIC は $k\log n$ の強い罰則で複雑さを抑えます。本ウィジェットの検証RMSE最小と、これら規準の最小が「だいたい一致し、時にズレる」ことを見比べると、モデル選択の全体像がつながります。関連: モデル選択 。