📚 背景知識(読んでから問題へ)
勝者の呪い(winner's curse)と候補数。 候補を K 本並べて CV の一番良いものを選ぶと、選ばれた1本の CV は実力より良く見える。CV には雑音があり、K 本の中で一番良く見えた1本は「実力が高い」か「雑音で得をした」かのどちらかだからだ。K が増えるほど、雑音で得をした候補が1位に来やすい。
雑音が互いに独立で、大きさ(標準偏差)が σ のとき、K 本の雑音の最小値の期待値はおよそ −σ√(2 ln K) になる(正規分布の極値の近似)。K=10 で 2.15σ、K=100 で 3.03σ、K=3,315 で 4.03σ。だから「候補を増やすと選択が雑音に引っ張られる」は理屈として正しい。
一方で、候補を増やすと箱の中に本当に良い候補が入る。問いは2つの綱引きになる:
| 量 | 候補を増やすと | 意味 |
|---|---|---|
| 箱の中の真の最良 | 下がる(良くなる) | 本当に良い候補が入る得 |
| 選び損(補正CV 最良の真の誤差 − 箱の中の真の最良) | 上がる(悪くなる) | 補正CV の雑音で、真の最良でない候補を選ぶ損 |
| 補正CV 最良の真の損 | どちらが勝つか次第 | 上の2つの和。これを最小にしたい |
混ぜた候補は独立ではない。 s31@600+s255@1,200 と s31@650+s255@1,200 は、予測がほとんど同じで、CV の雑音もほとんど同じ。独立な候補 K 本の式をそのまま使うと、選び損を大きく見積もる。実効的な候補数(K_eff)は K よりずっと小さい。
今日の前の決め方(CV設計書の該当部分)。
| 決定 | 中身 | 印(今日の前) |
|---|---|---|
| 8 | 決定20 の葉に knn 0.1 を混ぜた候補を入れる | ◎(重み 0.1 は HistGB で決めた値) |
| 12 | 2本目=公開LB最良(182本、1本目と同じなら2位) | ○ |
| 13 | 補正CV √(C² − A_test) で比べる。葉・本数・混ぜ(knn)に使える | ◎/○(混ぜ) |
| 22 | 1本目=単体52・knn 0.1 混ぜ52・葉ペア 50/50 同本数78 の182本から補正CV 最小 | ◎ |
Day182 で「1本目は182本から選ぶ」と決めたが、葉ペアは2つの葉を同じ本数・50/50 で混ぜただけだった。葉31 の単体の山は 1,200本より後ろ、葉255 は 400〜700本(Day181)で、同じ本数で混ぜる理由は無い。
今日の作り方。 Day182 と1文字も同じ学習(ワールドの乱数 3000+番号、40ワールド=低雑音16・小得12・中雑音12、lr0.05・1,200本の乱数なし LightGBM 葉 31/63/127/255 と k近傍)。学習は増やさず、集計する候補だけを増やす:
| 種類 | 本数 | 中身 | 箱 |
|---|---|---|---|
| 単体 | 52 | 葉4種 × 本数13点(600, 650, …, 1,200) | 箱0 |
| knn 混ぜ 0.10 | 52 | 単体 × 0.9 + knn × 0.1(決定8) | 箱1 |
| 葉ペア 同本数 50/50 | 78 | Day182 と同じ | 箱1 |
| knn 混ぜ 0.05/0.15 | 104 | 重みだけ変える | 箱2 |
| 3つ混ぜ・4つ混ぜ | 52+13 | 葉3種(4組)・4種、同本数、等重み | 箱2 |
| 葉ペア 本数別・重み別 | 2,964 | 6組 × 小さい葉の本数13 × 大きい葉の本数13 × 重み(小さい葉に)0.3/0.5/0.7(同本数50/50 を除く) | 箱3 |
箱は入れ子(箱1 = 箱0+Day182 の追加 = 182本、箱2 = 351本、箱3 = 3,315本)。
用語整理:
| 用語 | 意味 |
|---|---|
| 真の損 | 選んだ候補の T5(truth 6万行の RMSLE)− 3,315本の T5 の最小。×10⁻⁴ |
| 箱の中の真の最良 | その箱の T5 の最小 − 3,315本の T5 の最小 |
| 選び損 | 真の損 − 箱の中の真の最良(補正CV の雑音で外した分) |
| 楽観 | 選んだ候補の T5 − 補正CV(大きいほど、選ばれた候補の CV が良く見えすぎ) |
| 無作為 K 本の箱 | 3,315本から K 本を無作為に抜いた箱(K = 10〜3,315、各ワールド100回) |
数値はすべて縮小シミュレータの上の実測(S5E5 の構造を写した合成データ、Day163〜)。実データ(Kaggle Playground S5E5)では測っていない。
データ・保存物の構造(スキーマ)
| 名前 | 形・型 | 意味・作り方 | 使う場所 |
|---|---|---|---|
| Sex … Body_Temp, Dur_x_HR, Keytel_kcal, log_Dur | int / float | Day163〜182 と同じ合成(ワールドの乱数 3000+番号)。低雑音16・小得12・中雑音12。train 3万・元1.5万・test 2万・truth 6万 | 全候補 |
| oof5 / tst | (4, 13, 30000) / (4, 13, 20000) float32 | lr0.05 の葉31〜255 × 本数13点(600〜1,200)の OOF と test の5本平均(log、丸め前)。Day182 と完全一致 | 補正CV・公開/非公開 |
| oofk / tstk | (30000) / (20000) float32 | k近傍(15近傍・標準化・5列) | knn 混ぜ |
| S5 / SKW | (4,13,4) / (3,4,13,4) | 単体・knn 混ぜ(重み 0.05/0.10/0.15)の T5²・T1²・A_test・A_truth | 補正CV・真の誤差 |
| SPW | (6, 13, 13, 3, 4) float64 | 葉ペア 6組 × 小さい葉の本数 × 大きい葉の本数 × 重み 0.3/0.5/0.7(fold ごとに混ぜてから集計) | 箱3 |
| ST / SQ | (4,13,4) / (13,4) | 3つ混ぜ(4組)・4つ混ぜ、同本数・等重み | 箱2 |
| Wc | (53, 3315) | 集計側の係数行列(単体52+knn)。OOF・test は Wc.T @ X で全候補を一度に作る | analyze183.py |
| 保存先 | work/d183/r/{low,sm,mid}/raw183_w*.npz(計 353MB)・d183.pkl・a40.txt | tmp の外 | 次回以降 |
評価指標(RMSLE)と、今日の損の分け方
RMSLE は log1p 空間の RMSE(小さいほど良い)。差はすべて ×10⁻⁴。今日の中心は「補正CV 最良の真の損 = 箱の中の真の最良 + 選び損」の分解。下の図は入れ子の箱ごとの真の損。
❓ 問題
タスクA(理論: 測る前に式で予想する)
- 独立な K 本の雑音の最小値 ≈ −σ√(2 ln K) を使い、K=10 で選び損が 0.43×10⁻⁴ だったとき、K=3,315 の選び損を予想せよ(独立と仮定した場合)
- 実際の選び損が 1. の予想より小さいとしたら、その理由は何か。実効的な候補数 K_eff を、観測した選び損の比から逆算する式を書け
- 次の4つに「当たる/外れる」と理由を書く
- (a) 3,315本に広げると、補正CV 最良の真の損は182本より悪化する(勝者の呪い) - (b) 2本目の公開LB最良は、候補を補正CV 上位6本に絞った方が、3,315本全部から選ぶより得 - (c) 葉ペアの補正CV の偏り(単体との差)は、knn 混ぜより大きい - (d) knn の重みは 0.10 より 0.15 の方が良い
タスクB(コーディング)
day182.pyの学習部を1文字も変えずに、fold ごとの予測を混ぜてから truth を集計する候補を 3,315本に増やしたday183.pyを書く(A_test は fold ごとの予測の分散なので、混ぜた後でしか取れない)- Day182 の保存物と OOF・S5・SK・SP が一致することを確かめる(再現)
analyze183.pyで、箱0〜3 と無作為 K 本の箱の「真の損・箱の真の最良・選び損・楽観」、最終2本(公開20%・再分割200回)、knn の重み、種類ごとの補正CV の偏りを出す
タスクC(分析と決定)
- 決定22 の候補を何本まで広げるか。止め方を数字で書く
- 決定12(2本目)の候補の絞り方は、決定22 の上でも「広い方」でよいか
- 3,315本の補正CV 最良がどこに来たか(格子の端か)から、次に何を足すべきかを決める
💡 ヒント
ヒント1(方向性)
選び損だけを見ると「候補を増やすと悪い」に見える。真の損は「箱の真の最良」と「選び損」の和なので、両方を同じ K で並べる。無作為に K 本抜いた箱を何度も作れば、同じ候補の母集団の上で K だけを動かせる。
ヒント2(アプローチ)
混ぜた候補の OOF と test の5本平均は、log 空間で線形なので保存済みの単体から作れる(係数ベクトル × 単体の行列)。truth の T5 と A_test は fold ごとの予測が要るので、学習側で fold ごとに混ぜてから集計する。3,315本 × truth 6万行の集計は1ワールド約10秒。
独立な K 本なら選び損 ∝ √(2 ln K)。観測した比 r = 選び損(K₂)/選び損(K₁) から、K_eff は「√(2 ln K_eff₂)/√(2 ln K_eff₁) = r」を満たす。K₁=10 を基準に K_eff₁ = 10 と置けば、K_eff₂ = exp(r² ln 10)。
ヒント3(コード骨格)
# 学習側(day183.py): fold ごとの予測 E[葉, 本数, fold, 行] を混ぜてから集計 for p, (a, b) in enumerate(PAIRS): for i in range(nS): # 小さい葉の本数 for i2 in range(nS): # 大きい葉の本数 for q, wa in enumerate([0.3, 0.5, 0.7]): SPW[p, i, i2, q] = agg(wa * E[a, i] + (1 - wa) * E[b, i2]) # T5², T1², A_test, A_truth # 集計側(analyze183.py): 係数行列 Wc (53, N) で OOF と test を一度に作る Po = Wc.T @ Xo # (N, 3万)。Xo = [単体52本の OOF; knn の OOF] Ca = np.sqrt(((lpc(Po) - ytr) ** 2).mean(1) - S[:, 2]) # 補正CV T5 = np.sqrt(S[:, 0]) # 真 for K in [10, 30, 100, 300, 1000, 3315]: idx = rng.choice(N, K, replace=False); s = idx[np.argmin(Ca[idx])] loss, best = T5[s] - T5.min(), T5[idx].min() - T5.min() # 選び損 = loss - best
✅ 模範解答
タスクA(判定)
- 予想 0.81。 0.43 × √(2 ln 3,315)/√(2 ln 10) = 0.43 × 4.03/2.15 = 0.81。実測は 0.65(予想の 80%)
- 候補が似ているから。 観測した比 r = 0.65/0.43 = 1.51。K_eff = exp(1.51² × ln 10) = exp(5.25) ≈ 190。3,315本の候補の雑音は、独立な約190本ぶんしか散らばっていない(本数別・重み別の葉ペアは隣どうしでほぼ同じ予測)。この計算は K=10 の箱を「独立な10本」と置いた近似で、K=10 の箱の中にも似た候補はいるので、K_eff は上限寄りの目安
- 判定:
- (a) 外れ。 補正CV 最良の真の損は 箱1(182本)1.80 → 箱3(3,315本)0.65、対の差 −1.15±0.14(36/4)。選び損は増えたが、箱の真の最良がそれ以上に下がった - (b) 外れ。 1本目=3,315本の補正CV 最良の上で、2本目を CV 上位6本の公開最良にすると 0.84、3,315本全部の公開最良で 0.69(上位30本は 0.69 で同じ)。Day182 で「狭い6本が −0.22 良い」と出たのは、1本目が決定20(単体)で、2本目が混ぜを拾うかどうかの勝負だったため。1本目を混ぜにした後は、狭く絞る得は消えた(箱1 の上でも 上位6本 − 182本全部 +0.06±0.07) - (c) 外れ。 単体との対の偏り: 葉ペア −0.01±0.02、3つ混ぜ −0.01±0.03、knn 混ぜ +0.15±0.16。葉ペアは単体とほぼ同じ偏りで、補正CV でそのまま比べてよい - (d) 半分当たり。 決定20 の1本の上で、真の差は 0.05: −2.15±0.14、0.10: −3.23±0.27、0.15: −3.25±0.39。平均は同じだが、0.15 は低雑音で −0.73(0.10 は −1.49)と弱く、4ワールドで単体より悪化(0.10 は 0/40)。中雑音だけ見ると 0.15 が良い(−5.44 対 −4.75)
タスクB(完全なコード)
day183.py(学習部は Day182 と1文字も同じなので省略。全文は work/d183/day183.py):
E = ev5.astype(np.float64) # (4葉, 13点, 5 fold, test 2万 + truth 6万) S5 = np.array([[agg(E[j, i]) for i in range(nS)] for j in range(nM)]) # 単体 (4,13,4) WKS = [0.05, 0.10, 0.15] SKW = np.array([[[agg((1 - wk) * E[j, i] + wk * evk) for i in range(nS)] for j in range(nM)] for wk in WKS]) WP = [0.3, 0.5, 0.7] # 葉ペアの重み(小さい葉 a 側) SPW = np.zeros((len(PAIRS), nS, nS, len(WP), 4)) # a の本数 i × b の本数 i2 for p, (a, b) in enumerate(PAIRS): for i in range(nS): for i2 in range(nS): for q, wa in enumerate(WP): SPW[p, i, i2, q] = agg(wa * E[a, i] + (1 - wa) * E[b, i2]) TRI = [(a, b, c) for a in range(nM) for b in range(a + 1, nM) for c in range(b + 1, nM)] ST = np.array([[agg((E[a, i] + E[b, i] + E[c, i]) / 3) for i in range(nS)] for a, b, c in TRI]) SQ = np.array([agg(E[:, i].mean(0)) for i in range(nS)]) # 4つ混ぜ
analyze183.py の要部(全文は work/d183/analyze183.py):
# 候補 3,315本を係数ベクトル(53 = 単体52 + knn)で表す Wc = np.stack([c[2] for c in C], 1); S = np.stack([c[3] for c in C]) Po = Wc.T @ Xo; Ca = np.sqrt(((lpc(Po) - ytr) ** 2).mean(1) - S[:, 2]); T5 = np.sqrt(S[:, 0]) e = ((lpc((Wc.T @ Xt).astype(np.float32)) - yte) ** 2).T # test の二乗誤差 (2万, 3315) for b in range(4): # 入れ子の箱 idx = np.where(bx <= b)[0]; s = idx[np.argmin(Ca[idx])] B.append(dict(box=b, loss=T5[s] - T5.min(), orc=T5[idx].min() - T5.min(), opt=T5[s] - Ca[s])) M = np.zeros((200, 20000), np.float32) # 公開20% の再分割200回を行列にする for s_ in range(200): M[s_, rng.choice(20000, 4000, replace=False)] = 1 Ps = M @ e; P = Ps / 4000; Q = np.sqrt((e.sum(0) - Ps) / 16000) # 公開 MSE・非公開 RMSLE(全候補を一度に)
実行:
# 40ワールドを14並行で作る(run.sh は Day182 と同じ形。venv は work/d180/.venv) cd ~/AI/lab/学習/Engineer/DataScience/Kaggle/work/d183 xargs -P 14 -L 1 ./run.sh < jobs.txt # 集計(決定15 の葉は Day180 の d180.pkl、再現の照合は Day182 の raw182) ../d180/.venv/bin/python -W ignore analyze183.py r ../d182 ../d180 > a40.txt
実行結果(実測)
# ============ 実行環境: macOS・Apple M5 Pro(15コア・48GB)・uv venv(Python 3.13.16・lightgbm 4.7.0・scikit-learn 1.9.1、
# Day180 と同じ venv)。OMP_NUM_THREADS=1・n_jobs=1、14並行
# 40ワールド × (葉4種 + knn) × 5 fold = 1,000 fit(Day182 と同じ学習)+ 候補 3,315本の truth 集計
# 壁時計 7分08秒(04:12:42→04:19:50)、1ワールド 135〜144秒(Day182 は 121〜144秒。集計の増分は約10秒)
# 保存物 r/{low,sm,mid}/raw183_w*.npz 計 353MB(work/d183)。集計 62秒
ワールド数: {'中雑音': 12, '低雑音': 16, '小得': 12}
=== 表0 再現(Day182 の raw182 と最大絶対差、40ワールド)===
OOF 0.0e+00 S5 0.0e+00 SK(0.10) 0.0e+00 SP(同本数0.5) 0.0e+00
=== 表1 入れ子の箱: 補正CV最良の真の損 / 箱の中の真の最良(×1e-4、3,315本の真の最良からの差)===
箱 本数 低雑音 小得 中雑音 40ワールド 前の箱との対の差(良/悪)
箱0 単体 52 6.02 / 4.98 6.49 / 5.68 6.84 / 6.05 6.41±0.20 —
箱1 Day182 の182本 182 1.56 / 1.08 1.79 / 1.00 2.11 / 1.32 1.80±0.11 -4.61±0.21 (40/0)
箱2 +knn 重み・3つ/4つ混ぜ 351 1.60 / 1.04 1.64 / 0.85 1.03 / 0.48 1.44±0.12 -0.36±0.11 (17/4)
箱3 +葉ペア 本数別・重み別 3,315 0.65 / 0.00 0.83 / 0.00 0.47 / 0.00 0.65±0.12 -0.79±0.12 (29/4)
箱3 − 箱1: 低雑音 -0.91±0.14 小得 -0.97±0.31 中雑音 -1.64±0.23 40ワールド -1.15±0.14(36/4)。最悪の損 3.67 → 2.86
箱3 の補正CV最良の種類: 葉ペア 33・knn混ぜ 6・3つ混ぜ 1
=== 表2 無作為 K 本の箱(40ワールド平均、各ワールド100回)===
K 10 30 100 300 1000 3315
真の損 2.54 1.72 1.16 0.90 0.74 0.65
箱の最良 2.11 1.20 0.61 0.31 0.10 0.00
選び損 0.43 0.52 0.55 0.59 0.64 0.65
楽観 3.73 3.92 3.99 4.04 4.09 4.12 (候補全体の平均 T5−Ca は +2.95。選ばれた分の上乗せは 0.78 → 1.17)
[低雑音] 選び損 0.50→0.65 [小得] 0.49→0.83 [中雑音] 0.27→0.47
=== 表3 最終2本(公開20%・再分割200回): 最終スコアの損(非公開の良い方 − 3,315本の非公開最良)と 決定22+12 との対の差 ===
1本目 / 2本目 40ワールド 対の差(良/悪) 真の損(勝った方のT5) 対の差
182 CV最良 のみ 2.06 +0.29±0.08 (0/35) 1.80 +0.11±0.06
182 CV最良 + 公開最良182(決定22+12) 1.77 — 1.69 —
182 CV最良 + 公開最良(CV上位6本) 1.83 +0.06±0.07 (20/16) 1.70 +0.01±0.05
182 CV最良 + 公開最良3315 1.21 -0.56±0.07 (37/3) 1.16 -0.53±0.06
3315 CV最良 のみ 0.99 -0.78±0.15 (30/10) 0.65 -1.04±0.14
3315 CV最良 + 公開最良3315 0.69 -1.07±0.13 (38/2) 0.56 -1.13±0.11
3315 CV最良 + 公開最良(CV上位30本) 0.69 -1.07±0.13 (34/6) 0.53 -1.16±0.12
3315 CV最良 + 公開最良(CV上位6本) 0.84 -0.93±0.16 (33/7) 0.61 -1.08±0.14
3315 CV最良 + 公開最良182 0.89 -0.88±0.13 (32/8) 0.66 -1.02±0.13
3315 CV最良 + CV最良182 0.92 -0.85±0.14 (33/7) 0.72 -0.97±0.13
3315 CV 1位 + 2位 0.93 -0.83±0.15 (34/6) 0.62 -1.07±0.13
=== 表4 knn の重みを決定20 の1本の上で(真の差 ×1e-4、ワールド平均±SE、良/悪)===
重み 低雑音 小得 中雑音 40ワールド 補正CV の対の偏り
0.05 -1.25±0.09 -2.56±0.13 -2.94±0.15 -2.15±0.14 (40/0) +0.10±0.09
0.10 -1.49±0.17 -4.03±0.26 -4.75±0.29 -3.23±0.27 (40/0) +0.21±0.17
0.15 -0.73±0.25 -4.41±0.37 -5.44±0.42 -3.25±0.39 (36/4) +0.32±0.26
=== 表5 種類ごとの補正CV の偏り(Ca−T5 の種類内平均の、単体との対の差、×1e-4)===
葉ペア -0.01±0.02 3つ混ぜ -0.01±0.03 4つ混ぜ -0.01±0.03 knn混ぜ +0.15±0.16
(偏りそのもの Ca−T5 は単体で -2.95±2.29。ワールドごとの train の引き方で決まり、種類ではほぼ動かない)
=== 表6 箱3 の補正CV最良(葉ペア 33本)は格子の端にいるか ===
小さい葉の本数: 600本(下端)18・1,200本(上端)0
大きい葉の本数: 600本(下端)0・1,200本(上端)27
重み(小さい葉に): 0.5 が16・0.3 が13・0.7 が4 組: s31+s255 が29・s31+s127 が4
名前上位: s31@600 x0.3 + s255@1200 が 9ワールド
タスクC(分析と決定の模範)
- 決定22 の候補を 3,315本に広げる(改訂、◎)。 箱1 → 箱3 で −1.15±0.14(36/4、3世界とも 2SE 超)。学習は同じ(4葉+knn)で、増えるのは集計だけ(1ワールド約10秒、182本の時の 1.1倍)。得の大半は「葉ペアの本数を別々にする」(箱2 → 箱3 で −0.79±0.12)。knn の重み・3つ混ぜを足す箱2 は −0.36±0.11 と小さい
- 止め方は「箱の最良の下がり幅 < 選び損の上がり幅」。 表2 で K を3倍強にするごとに、箱の最良は 0.91 → 0.59 → 0.30 → 0.21 → 0.10 下がり、選び損は 0.09 → 0.03 → 0.04 → 0.05 → 0.01 上がる。3,315本ではまだ下がり幅(0.10)が上がり幅(0.01)より大きい。ただし1,000 → 3,315 の真の損の得は 0.09 しかなく、次に10倍(3万本)にしても得は 0.1 前後と見込む(外挿、未計測)。本数を増やすより、表6 の端を直す方が先
- 2本目は3,315本全部の公開LB最良(決定12 改訂、○)。 1本目=3,315本の補正CV 最良の上で、2本目の得は非公開 0.99 → 0.69(−0.30)、真の損では 0.65 → 0.56(−0.09、得の3割)。Day182(真で残るのは4割弱)と同じく、2本目の得の大半は非公開の雑音の運。CV 上位6本に絞ると 0.84 と得が半分になる。上位30本は全部と同じ 0.69。Day182 の「狭い方が得」は1本目が単体だったときだけの話で、撤回
- 格子の端(持ち越しの最重要)。 3,315本の補正CV 最良の葉ペア33本のうち、小さい葉は 18本が下端の600本、大きい葉は 27本が上端の1,200本。単体の山(葉31 は 1,200本の後ろ、葉255 は 400〜700本、Day181)と逆向きに端へ寄る。混ぜの部品は単体として最良である必要はなく、「小さい木は浅く(少ない本数)、大きい木は深く(多い本数)」して互いの間違え方を離した方が得、と読める。決定15 の「端が勝ったら1本足す」と同じ止め方で、次回は葉31 の 300〜550本と葉255 の 1,250〜2,000本を足す
- knn の重みは 0.05/0.10/0.15 の3点を全部候補に入れる(決定8 改訂、◎)。 平均では 0.10 と 0.15 が同じ(−3.23 対 −3.25)だが、世界で向きが違う(低雑音は 0.10、中雑音は 0.15)。1つに決めずに候補にして補正CV に選ばせる。偏りは +0.10〜+0.32(どれも 2SE 未満)
- 補正CV は葉ペア・3つ混ぜにも使える(決定13 追記、◎)。 単体との対の偏り −0.01±0.02(葉ペア)・−0.01±0.03(3つ混ぜ)
タスクC-4(CV設計書の差分、2026-10-16 版)
決定1〜22 のうち、今日変えた行だけを書く(他は Day182 の表のまま)。
| # | 項目 | 今の決め方 | 印 | 根拠(測った数字) | 前提が変わったら |
|---|---|---|---|---|---|
| 8 | 混ぜる(knn) | knn の重み 0.05/0.10/0.15 の3点を決定22 の候補に入れる | ◎ | 決定20 の上で 0.05 −2.15・0.10 −3.23・0.15 −3.25(0.15 は 4/40 で悪化) | 0.20 以上は未計測(中雑音では 0.15 が最良で、端) |
| 12 | 最終2本 | 1本目=決定22、2本目=3,315本全部の公開LB最良(1本目と同じなら2位) | ○ | 決定22+12(182本)より −1.07±0.13(38/2)。2本目の得 −0.30 のうち真で残るのは −0.09。CV 上位6本に絞ると 0.84 対 0.69 で悪い | 候補が1桁増えたら測り直す。公開割合 5/50% は今日の箱では未計測(Day182 の 182本では得は縮むが損はしない) |
| 13 | CV の直し方 | 補正CV で比べる。葉・本数・混ぜ(knn・葉ペア・3つ/4つ)に使える。早期打ち切りには使えない | ◎ | 単体との対の偏り 葉ペア −0.01±0.02、3つ混ぜ −0.01±0.03、knn +0.15±0.16 | 重みを連続で最適化した混ぜは未計測 |
| 22 | 1本目 | 葉 31/63/127/255 を lr0.05・1,200本で1回ずつ学習し、単体52・knn 混ぜ156(重み3点)・葉ペア 6組×本数13×13×重み3(2,964+同本数78)・3つ混ぜ52・4つ混ぜ13 の3,315本から補正CV 最小 | ◎ | 182本より −1.15±0.14(36/4)、真の損 0.65(最悪 2.86)。選び損 0.65(独立なら 0.81、K_eff ≈ 190) | 補正CV 最良が格子の端(小さい葉 600本・大きい葉 1,200本)に寄っている。端を広げて測り直す(次回) |
タスクD(今日の決定の記録)
| # | 決定 | 採った案 | 採らなかった案と理由 | 前提が変わったら |
|---|---|---|---|---|
| 22(改訂、◎) | 候補を3,315本に広げる | 182本より −1.15±0.14、選び損は 0.65 で止まる | (a) 182本のまま: 36/40 で負ける。(b) 重みを OOF で連続最適化(scipy の最小化): 候補が無限になり、選び損が K_eff で測れない。格子3点で −0.79 取れたので、連続にする前に端を直す。(c) 3万本へ: 1,000→3,315 の得が 0.09 で、次の10倍の得は 0.1 前後の見込み。集計は10倍(1ワールド約100秒)かかる | 候補の種類が増えて K_eff が数千を超えたら、選び損の伸びを測り直す(独立なら √(2 ln K) で伸びる) |
| 12(改訂、○) | 2本目は3,315本全部の公開最良 | 0.69(上位30本と同じ)、6本は 0.84 | (a) CV 上位6本の公開最良(Day182 の狭い案): 1本目が混ぜなら得が半分。(b) 補正CV 2位: 0.93 で、1位と似た候補なので保険にならない(真の損 0.62 は公開最良の 0.56 より悪い) | 公開が時期で分かれる(ランダムでない)コンペでは、公開最良が非公開と別の方向に合わせる危険を測り直す |
| 8(改訂、◎) | knn 重みは3点を候補に | 世界で最良の重みが違う | 0.10 に固定: 中雑音で −0.69 取り逃す。0.15 に固定: 低雑音で +0.76 損、4/40 で単体より悪化 | — |
| 13(追記、◎) | 補正CV は葉ペア・3つ混ぜにも使える | 偏り −0.01 | 混ぜ用の別の補正: 不要(差が 0.02 以下) | — |
📊 結果の可視化
1枚目: 候補を増やすと選び損(橙)は確かに増えるが、箱の真の最良(青)がそれ以上に速く下がり、真の損(白)は単調に下がる。橙の点線は独立と仮定した予想で、実測は予想の 80%。2枚目: 得の大半は1本目を3,315本から選ぶこと(−0.78)。2本目を3,315本全部の公開最良にするとさらに −0.29。CV 上位6本に絞ると得が減る。
🪜 Step-by-Step 解説
Step 1: 再現を先に確かめる
学習部を Day182 から1文字も変えず、候補の集計だけ足した。40ワールドで OOF・S5・knn 混ぜ 0.10・同本数 50/50 の葉ペアが Day182 の保存物と完全一致(差 0.0)。今日の数字は Day182 と同じモデルの上の比較になっている。
Step 2: 混ぜた候補の truth は学習側で作る
OOF と test の5本平均は log 空間で線形なので、単体を係数で混ぜれば作れる(集計側)。だが補正CV に要る A_test(fold ごとの予測の分散)と、真の T5 の切り詰め(clip)は線形でないので、fold ごとの予測を混ぜてから集計する必要がある。3,315本 × truth 6万行で1ワールド約10秒増えただけ。
Step 3: 入れ子の箱で「どこから得が来たか」を分ける(表1)
箱1 → 箱2(knn 重み・3つ混ぜ)は −0.36、箱2 → 箱3(葉ペアの本数別・重み別)は −0.79。得の7割は「2つの葉を別々の本数で混ぜる」から来た。
Step 4: 無作為 K 本の箱で、真の損を2つに分ける(表2)
K を 10 → 3,315 にすると、選び損は 0.43 → 0.65 と確かに増える(勝者の呪いは実在する)。しかし箱の真の最良は 2.11 → 0 と速く下がるので、和の真の損は単調に下がる。式(独立)の予想 0.81 より実測 0.65 が小さいのは、候補が似ていて K_eff ≈ 190 だから。
Step 5: 「楽観」の読み方を間違えない
選ばれた候補の T5 − Ca は 3.73〜4.12 と大きく見えるが、その大部分(+2.95)は候補全体に共通の偏り(その世界の train の引き方で CV が全員そろって良く見える分、Day177 の項1)。選んだことによる上乗せは 0.78 → 1.17。選択の上振れは、候補全体の偏りと分けて読む。
Step 6: 選ばれた候補の場所を見る(表6)
3,315本の補正CV 最良は、小さい葉の下端(600本)と大きい葉の上端(1,200本)に寄った。格子の端で最良が出たら、格子が足りないという合図(Day176 の葉511 と同じ理屈)。
📐 数学・統計の補足(文系向け)
√(2 ln K) はどこから来るか。 くじを K 回引いて一番小さい数を取ると、引く回数が増えるほど小さい数が出やすい。ただし増え方はゆっくりで、10回 → 100回で 2.15 → 3.03、100回 → 3,315回でも 3.03 → 4.03 にしかならない。「候補を30倍にしても、雑音による上振れは3割増えるだけ」。一方、本当に良い候補が入る得は、候補の作り方次第でずっと大きくなりうる。今日はこちらが勝った。
K_eff(実効的な候補数)。 30人の生徒に同じ問題を解かせても、全員が同じ参考書で勉強していたら、答えのばらつきは数人分しかない。似た候補は「同じ参考書の生徒」で、雑音もそろって動く。3,315本の雑音の散らばりは、独立な約190本ぶんだった。
なぜ「小さい木は浅く、大きい木は深く」なのか。 混ぜで効くのは、2本の間違え方が違うこと(Day166・182)。葉31 の600本は大まかな形しかつかまない、葉255 の1,200本は細部(雑音も含む)まで覚える。この2つの間違え方は大きく離れている。単体として最良(葉31 は長く、葉255 は短く)にすると、2本は似た形に近づき、混ぜる得が減る。部品の最良と、混ぜの最良は別物。
🏆 Kaggleでの実践的な使い方
- 混ぜの候補は、部品ごとの本数を別々に作る。 同じ本数・同じ重みで混ぜるだけだと得の7割を取り逃す(今日の −0.79 対 −1.15)。学習は増やさず、保存した途中本数の予測を組み合わせるだけでよい(LightGBM の
start_iteration/num_iterationで途中の予測を取る、Day179〜) - 候補数を増やすことを恐れすぎない。 補正CV(fold 分散の補正)で比べるなら、3,315本でも選び損は 0.65 で止まった。ただし「候補が似ている」ことが前提(K_eff ≈ 190)。全く違う系統のモデルを数千本並べる場合は K_eff が大きくなり、選び損も大きくなる
- 最良が格子の端に来たら、格子を広げる合図。 混ぜの部品は単体の山と逆の方向に端へ寄ることがある
- 2本目は候補全部の公開LB最良。 1本目が混ぜの補正CV 最良なら、2本目の候補を絞る理由は無い。ただし2本目の得の大半は非公開の雑音の運で、手法の比較には使わない
- 公開ノートブックでよく見る「hill climbing で重みを探す」は、今日の格子3点より細かい探索で、選び損が増える側の操作。格子でまず端を直し、その後に比べる
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| 候補を増やすと勝者の呪いで必ず悪くなる | 選び損だけを見る | 選び損は 0.43 → 0.65 と増えるが、箱の真の最良が 2.11 → 0 と速く下がる。和は単調に良くなった |
| 選び損は √(2 ln K) どおりに増える | 候補を独立と見なす | 似た候補は雑音も似る。3,315本で K_eff ≈ 190、実測は式の 80% |
| 選ばれた候補の CV と真の差(楽観)が全部、選択の上振れ | 全員に共通の偏りと区別しない | 楽観 4.12 のうち 2.95 は候補全体に共通。選択の上乗せは 1.17 |
| 混ぜの部品は単体として最良の本数にする | 部品が強ければ混ぜも強いと思う | 補正CV 最良は、葉31 は短く(600本)、葉255 は長く(1,200本)。単体の山と逆向き |
| 2本目は候補を絞った方が公開LB に合わせすぎない | Day182 の「狭い6本が得」をそのまま使う | 1本目が混ぜなら、6本に絞ると得が半分(0.84 対 0.69) |
| knn の重みは1つに決める | 平均で一番良い値を探す | 世界で最良の重みが違う(低雑音 0.10、中雑音 0.15)。3点とも候補にして補正CV に選ばせる |
🧭 扱わなかった範囲と理由
- 格子の外側: 葉31 の 600本未満・葉255 の 1,200本超は今日の保存物に無い(600〜1,200 の13点だけ保存)。表6 で端に寄ったので次回に回す。今日の「3,315本の真の最良」は格子の中の最良で、端を広げればもっと良い候補がありうる
- 重みの連続最適化(scipy の最小化・hill climbing): 選び損が K_eff で測れなくなるため。格子の端を直してから比べる
- 3つ混ぜの本数別・重み別: 13³×重みで数万本になり、今日の問い(182本 → 数千本)の外。3つ混ぜ(同本数・等重み)は 1/40 でしか選ばれなかった
- 公開割合 5%・50%: 今日の最終2本は公開20% だけ(Day182 の182本では 5〜50% で向きは同じだった)
- K_eff の直接推定: 候補の補正CV の相関行列の固有値から K_eff を出す方法はある(Nyholt 2004 の有効検定数など)が、今日は選び損の比からの逆算だけ。原典は照合していない
- 極値の近似 √(2 ln K): 正規分布の最大値の標準的な漸近近似として記憶に基づいて使った。原典は照合していない
- 持ち越し: 1,200本より先、早期打ち切りの入れ子、学習率 0.02 以下、seed を変えた独立な10分割、mcs 5・10、乱数ありの候補(決定14)、avg3、noKeytel・raw7、入れ子CV との比較、Kaggle 最終提出規則と S5E5 ルールの原文照合
- 実データ(S5E5): 縮小シミュレータの上の数字のみ。Kaggle のログインとルール同意が要るので、利用者の作業として残す
🚀 次のステップ
- 発展: 補正CV の相関行列から K_eff を直接出し、選び損の √(2 ln K_eff) 予想と比べる
- 発展: 重みを 0.1 刻み(0.1〜0.9)にしたとき、選び損の増え方が K_eff でどれだけ伸びるか
- 次回予告: Day 184 — Playground Series 実戦投入⑲(格子の端を広げる: 葉31 を 300〜550本、葉255 を 1,250〜2,000本まで保存して葉ペアを作り直し、補正CV 最良が端から離れるか、真の損がさらに下がるかを40ワールドで測る)。月替わりテーマ3「画像(CV)系コンペへの応用」は 10/25 から
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: