📚 背景知識(読んでから問題へ)
Day176 で残った疑い。 補正CV は「生の CV² から、test 行の fold 間分散 A_test を引いて √ を取る」もの(決定13、Day171)。Day176 の途中集計(9ワールド)では、大きい木で補正が効きすぎて見えた。
| 世界(ワールド数) | 葉511 の生の偏り | 補正後の残り |
|---|---|---|
| 低雑音(3) | +22.04 | −4.78±1.76(約 2.7SE) |
| 小得(1) | +23.84 | −10.68(SE なし) |
| 中雑音(5) | +42.29 | +3.23±3.06 |
(×10⁻⁴、lgb_det=葉31 との差。「偏り」= CV の差 − 真の差。プラスは「CV が大きい木を実際より悪く見せる」)
Day176 の仮説は「A_test を fold 5個の分散で推定する誤差が、大きい木で増えている」だった。今日はこれを式で先に分解し、どの項が残りを作っているかを測る。
用語整理:
| 用語 | 意味 |
|---|---|
| C² | 生の CV の二乗。1本のモデルが自分の担当外(OOF)の train 行 30,000 行で出した二乗誤差の平均(log1p 空間) |
| T1 | 5本のモデルそれぞれで truth 60,000 行を採点した二乗誤差の、5本の平均 |
| T5² | 5本の予測の平均(=提出)で truth を採点した二乗誤差。これが「真」 |
| A_test / A_truth | 5本の予測の分散(行ごとに5個の分散を取り、行で平均)。test 20,000 行で測るか、truth 60,000 行で測るか |
| 補正CV Ca | √(C² − A_test)(決定13) |
| 残り | 補正CV の差 − 真の差(対 lgb_det)。0 なら補正が正しい |
数値はすべて縮小シミュレータの上の実測(S5E5 の構造を写した合成データ、Day163〜)。実データで同じになるとは限らない。
データ・保存物の構造(スキーマ)
| 名前 | 形・型 | 意味・作り方 | 使う場所 |
|---|---|---|---|
| Sex … Body_Temp, Dur_x_HR, Keytel_kcal | int / float(9列) | Day163〜176 と同じ合成(ワールドの乱数 3000+番号)。Calories の雑音だけ 0.05/0.03(低)・0.12/0.08(小得)・0.15/0.10(中) | 全候補 |
| raw176_w*.npz(今日の31+Day176 の9) | oof (6,30000)・evk (6,5,80000) float32・fit_s (6,) | 乱数なしの葉127/255/511 × mcs 20/50。今日 31 ワールド × 6本 × 5 fold = 930 fit を追加し 40 ワールドがそろった | 表1〜3・6・7 |
| raw175(葉31/63/127) | oof (3,30000)・evk (3,5,80000) | Day175 の保存物。今日の leaf127 と最大差 0.0 | 表0〜3・6・7 |
| raw177_w*_k{5,10}_s{0,1}.npz | oof (3,30000)・evk (3,K,80000) | 今日の分割違い: 葉31/127/511 を、分割 seed 1 の5分割と10分割で作り直し(低・中雑音 各6ワールド、375 fit) | 表4・5 |
| C² / T1 / T5² / A_test / A_truth | float | OOF 3万行の二乗誤差/5本それぞれの truth 6万行の誤差の平均/5本平均の truth 誤差/5本の分散(test 2万行・truth 6万行) | 3項の分解 |
評価指標(RMSLE)と、補正CV の分解
RMSLE は log1p 空間の RMSE(小さいほど良い)。補正CV は √(C² − A_test)。恒等式 T1 − T5² = A_truth から、補正CV と真の差は Ca² − T5² = (C² − T1) + (A_truth − A_test) + 切り詰め に分かれる。下の図は、Day176 で「効きすぎ」に見えた葉511 の残りが、40ワールドでどうなったかと、そのうち A の推定誤差(項2)の大きさ。
❓ 問題
タスクA(理論)— 測る前に式で分ける
- 行ごとに、5本の予測を p₁…p₅、平均を p̄、正解を y とする。「5本それぞれの二乗誤差の平均 − 平均の二乗誤差 = 5本の分散(÷5 で割る分散)」が近似ではなく恒等式であることを示せ
- 1 を使って、補正CV の二乗と真の二乗の差 Ca² − T5² を、意味のある3つの項に分けよ
- Day176 の仮説(A の推定誤差が大きい木で増える)が正しいなら、どの項が大きくなるはずか。fold 数を 5→10 にしたら何が変わるか予想せよ
タスクB(コーディング)
- 3つの項を40ワールド(低雑音16・小得12・中雑音12)× 乱数なし8本で測る
analyze177.pyを書く。恒等式が数値でも成り立つこと(切り詰め無しで差が 1e-15 未満)を確かめる - 残りの揺れが「OOF を採点する行の引き方」で説明できるかを、行ごとの二乗誤差の差の SD から予測した SD と、ワールド間で実測した SD を並べて確かめる
- 分割だけを変えた作り直し(
day177.py: 分割 seed 1 の5分割、10分割)を低雑音・中雑音 各6ワールドで回し、同じワールドで残りが同じ向きに出るかを見る
タスクC(戦略)
- 決定13(補正CV)の印をどうするか
- 残りの揺れが基準選び(決定15)の選び間違いを生むなら、「引き分けなら小さい木」を足すと得か
- 残りの揺れを減らすには、分割を繰り返すのと、行を増やすのと、どちらが効くか
💡 ヒント
ヒント1(方向性)
「同じ行で測った分散」と「別の行で測った分散」は違う。補正CV が引いているのは test 行の分散で、真を作っているのは truth 行。そして生の CV は、さらに別の train 行で採点している。
ヒント2(アプローチ)
恒等式は「平均からのずれの二乗和は、クロス項が 0 になる」で示せる(分散の分解と同じ)。すると Ca² − T5² = (C² − T1) + (A_truth − A_test) + (切り詰めによるずれ) になる。A の推定誤差は第2項にしか入らない。
ヒント3(コード骨格)
def decomp(y, ytru, O, E): # O: OOF (30000,) E: fold 別予測 (5, 80000) c2 = ((lp_clip(O) - np.log1p(y)) ** 2).mean() Et, Eu = E[:, :N], E[:, N:]; lu = np.log1p(ytru) t1 = ((lp_clip(Eu) - lu) ** 2).mean() # 5本それぞれの truth 誤差の平均 t5 = ((lp_clip(Eu.mean(0)) - lu) ** 2).mean() # 平均の truth 誤差 a_te, a_tr = Et.var(axis=0).mean(), Eu.var(axis=0).mean() ident = ((Eu - lu) ** 2).mean() - ((Eu.mean(0) - lu) ** 2).mean() - a_tr # 切り詰め無しなら 0 return c2, t1, t5, a_te, a_tr, ident
✅ 模範解答
タスクA(理論)
1. 恒等式。 行を1つ固定し、dₖ = pₖ − y、d̄ = p̄ − y とする。
(1/5) Σ dₖ² = (1/5) Σ (d̄ + (pₖ − p̄))² = d̄² + (2d̄/5) Σ (pₖ − p̄) + (1/5) Σ (pₖ − p̄)²
真ん中の Σ (pₖ − p̄) は平均の定義から ちょうど 0。よって
5本の誤差の平均 − 平均の誤差 = (1/5) Σ (pₖ − p̄)²(÷5 の分散)
が、データの分布にも fold 数にも関係なく成り立つ。行で平均しても成り立つので T1 − T5² = A_truth(truth 行の分散)。実測でも切り詰め無しの差は最大 1.39×10⁻¹⁷(40ワールド × 8本、浮動小数の丸めだけ)。
2. 3つの項。 Ca² − T5² = C² − A_test − T5² に T5² = T1 − A_truth(+切り詰め項)を入れると
| 項 | 式 | 意味 | 期待値 |
|---|---|---|---|
| 項1 | C² − T1 | 同じ5本のモデルを、OOF の train 行で採点するか truth 行で採点するかの差 | 0(train 行も truth 行も同じ母集団から独立に引いている) |
| 項2 | A_truth − A_test | 同じ5本の分散を、truth 行で測るか test 行で測るかの差 | 0(同じ母集団の別の行) |
| 項3 | 切り詰め | 予測を exp 側で 1 未満にしない clip のせいで恒等式からずれる分 | ほぼ 0 |
3. 予想。 Day176 の仮説が正しければ項2が大きい木で大きくなるはず。ところが1の恒等式から、「fold 5個の分散」は5本平均の得をちょうど表す量で、推定のための近似ではない。A の誤差になりうるのは「test 行 20,000 行の引き方」だけで、これは行数が多いので小さいと予想する。fold 数を 10 にしても、恒等式は「10本の分散」で同じように成り立つので、偏りは生まれないと予想する(ただし生の偏りの大きさは変わる)。
タスクB(完全なコード)
analyze177.py(要点。全文は保存物 analyze177.py):
def decomp(y, ytru, O, E, rng, e_ref, u_ref): eo = (lp_clip(O) - np.log1p(y)) ** 2 # OOF 行ごとの二乗誤差 c = eo.mean() Et, Eu = E[:, :N], E[:, N:] a_te = Et.var(axis=0).mean(); a_tr = Eu.var(axis=0).mean() lu = np.log1p(ytru) eu = ((lp_clip(Eu) - lu) ** 2).mean(0) # truth 行ごとの、5本の二乗誤差の平均 t1 = eu.mean() t5 = ((lp_clip(Eu.mean(0)) - lu) ** 2).mean() t1n = ((Eu - lu) ** 2).mean(); t5n = ((Eu.mean(0) - lu) ** 2).mean() # 切り詰め無し av = Et.var(axis=0) # test 行数を減らした A_test(200回抜き直し) sub = {n: np.array([av[rng.choice(N, n, replace=False)].mean() for _ in range(200)]) for n in (2000, 5000)} return dict(C2=c, T1=t1, T5sq=t5, Ate=a_te, Atr=a_tr, ident=(t1n - t5n) - a_tr, Ca=np.sqrt(c - a_te), T5=np.sqrt(t5), C=np.sqrt(c), A2k_sd=sub[2000].std(), A5k_sd=sub[5000].std(), sd_diff_row=(eo - e_ref).std() if e_ref is not None else np.nan, # 対 lgb_det sd_diff_tru=(eu - u_ref).std() if u_ref is not None else np.nan), eo, eu # 二乗の差を RMSLE の差に換算: Δ√x ≈ Δx / (2√x) k2 = 1e4 / (2 * T5[c]) resid = ((Ca[c] - Ca["lgb_det"]) - (T5[c] - T5["lgb_det"])) * 1e4 t1 = ((C2[c] - C2["lgb_det"]) - (T1[c] - T1["lgb_det"])) * k2 t2 = ((Atr[c] - Atr["lgb_det"]) - (Ate[c] - Ate["lgb_det"])) * k2 t3 = resid - t1 - t2 # 行の引き方だけで説明できるときの SD(OOF 30,000行と truth 60,000行は別の行なので分散を足す) pred_sd = np.sqrt(sd_diff_row**2 / 30000 + sd_diff_tru**2 / 60000) / (2 * T5[c]) * 1e4
day177.py(day176.py の生成部を1文字も変えず、候補を3本・分割を引数にしただけ):
KF, SS = map(int, sys.argv[4].split(",")) # fold 数と分割 seed DET = [("lgb_det", dict()), ("leaf127", dict(num_leaves=127)), ("leaf511", dict(num_leaves=511))] evk = np.zeros((len(names), KF, N_TEST + N_TRUTH), np.float32) for k, (tr, va) in enumerate(KFold(KF, shuffle=True, random_state=SS).split(train)): ... # 学習部は day176.py と同じ np.savez_compressed(f"raw177_w{W}_k{KF}_s{SS}.npz", oof=oof, evk=evk, ...)
実行:
# 新しい uv venv(Python 3.13.12・lightgbm 4.7.0・numpy 2.5.3・pandas 3.0.6・scikit-learn 1.9.1)を作る(Day172 の venv は tmp の掃除で壊れていた) uv venv -p 3.13 .venv && uv pip install -p .venv/bin/python lightgbm==4.7.0 numpy==2.5.3 pandas==3.0.6 scikit-learn==1.9.1 scipy==1.18.1 # Day176 の残り31ワールドを 6 並行で作る(run.sh は scikit-learn 同梱の libomp を DYLD_LIBRARY_PATH に入れて呼ぶ) (for w in $(seq 1 11); do echo "$w 0.12 0.08 sm"; done; for w in $(seq 5 11); do echo "$w 0.15 0.10 mid"; done; for w in $(seq 3 15); do echo "$w 0.05 0.03 low"; done) | xargs -P 6 -L 1 sh -c './run.sh day176.py $0 $1 $2 '"$(pwd)"'/r176/$3' # 分割だけを変えた作り直し(再現確認1本+低・中雑音 各6ワールド × 2設定)を 5 並行で (echo "0 0.05 0.03 low 5,0"; for w in 0 1 2 3 4 5; do for c in 5,1 10,0; do echo "$w 0.05 0.03 low $c"; echo "$w 0.15 0.10 mid $c"; done; done) | xargs -P 5 -L 1 sh -c './run.sh day177.py $0 $1 $2 '"$(pwd)"'/r177/$3 $4' # 集計(3分解・Day176 の表の出し直し・分割の比較・引き分けルール) python analyze177.py <d175> <d176> r176 && python update176.py && python analyze177b.py <d175> <d176> r176 r177 && python tie177.py <d175> <d176> r176
実行結果(実測)
# ============ 実行環境: macOS (M1, メモリ8GB)・新しい uv venv(バージョンは Day172〜176 と同じ)
# OMP_NUM_THREADS=1・n_jobs=1。他のセッション(VM・go test)と同居し load average 7〜290
# Day176 残り31ワールド × 6本 × 5 fold = 930 fit、壁時計 3,163 秒(1ワールド 442〜624 秒)
# day177.py: 25 回(再現1+12ワールド×2設定)、lgb_det/葉127/葉511 × 5 or 10 fold = 375 fit、壁時計 1,386 秒
=== 表0 再現(決定9)===
今日の leaf127(31ワールド)対 raw175 の leaf127: OOF・fold 別予測とも最大差 0.0(3世界とも)
day177.py の K=5・分割seed 0(低雑音 w0)対 保存物(葉31・127・511): 最大差 0.0
恒等式 T1−T5²−A_truth(切り詰め無し)の最大絶対値: 1.39e-17
=== 表1 補正CV の残り(対 lgb_det、×1e-4、平均±SE)と3項の分解(40ワールド)===
残り 項1 OOF−truth 項2 A 項3 切り詰め
[低雑音 n=16]
leaf63 +0.33±1.07 +0.30±1.05 +0.04 -0.01
leaf127 +2.04±1.28 +1.82±1.27 +0.24 -0.02
leaf255 +2.78±1.75 +2.60±1.72 +0.20 -0.03
leaf511 +3.15±1.96 +2.96±1.92 +0.21 -0.02
leaf255_m50 +2.97±1.49 +2.93±1.43 +0.05 -0.01 ← 21組で最大の 2.0SE
[小得 n=12]
leaf127 +1.20±1.44 +1.23±1.36 +0.05 -0.08
leaf255 +1.15±1.94 +1.17±1.93 +0.06 -0.08
leaf511 +0.35±2.50 +0.37±2.42 +0.05 -0.06
[中雑音 n=12]
leaf127 -0.00±1.73 +0.00±1.73 +0.07 -0.07
leaf255 +0.86±2.09 +0.95±2.00 +0.00 -0.09
leaf511 +1.34±2.24 +1.17±2.16 +0.24 -0.07
(項2 のワールド間 SD は最大 0.70、項3 の絶対値は最大 0.09。21組すべてで「残り ≒ 項1」)
=== 表2 A_test の推定の揺れ(二乗の尺度 ×1e-4、200回抜き直しの SD)===
[中雑音] lgb_det: A 5.87 (2千行 0.237 / 5千行 0.137) leaf511: A 23.34 (2千行 0.637 / 5千行 0.369)
(A は葉511 で lgb_det の約4倍に育つが、2万行での揺れは A の 1% 台)
=== 表3 項1 の揺れ: 行の引き方だけから予測した SD と、ワールド間の実測 SD(×1e-4)===
[低雑音] leaf63 3.12/4.19 leaf127 4.34/5.08 leaf255 5.36/6.89 leaf511 6.08/7.67
[小得] leaf63 2.75/3.42 leaf127 3.96/4.72 leaf255 5.16/6.67 leaf511 6.14/8.37
[中雑音] leaf63 2.75/2.98 leaf127 4.04/5.99 leaf255 5.35/6.94 leaf511 6.48/7.50
(予測 / 実測。予測は実測の 67〜92%。木が大きいほど両方とも大きい)
=== 表4 分割を変えた作り直し(各6ワールド、×1e-4): 残りの平均±SE ===
[低雑音] leaf127: K5s0 +1.94±2.47 K5s1 +0.67±2.29 K10s0 -0.26±2.49
leaf511: K5s0 +2.99±3.79 K5s1 +0.33±1.79 K10s0 +0.73±3.54
[中雑音] leaf127: K5s0 -0.73±2.87 K5s1 +0.39±1.84 K10s0 +2.48±1.39
leaf511: K5s0 +2.62±2.57 K5s1 +0.44±1.97 K10s0 +2.66±2.52
生の偏り(参考): 中雑音 leaf511 K5 +41.55 / +39.80、K10 +34.59
=== 表5 同じワールドで、分割を変えても残りは同じ向きか ===
K5s0×K5s1 相関 分割ごとの揺れ SD 2回平均の SD
[低雑音] leaf127 +0.74 3.00 5.44
[低雑音] leaf511 +0.34 6.25 5.77
[中雑音] leaf127 +0.77 3.24 5.44
[中雑音] leaf511 +0.43 4.28 4.72
(K5s0×K10s0 の相関 0.82〜0.98 は使わない: 同じ分割 seed の KFold は 10 分割の各 fold が 5 分割の fold の半分になる入れ子で、独立な分割ではない。10個すべてで包含を確認)
=== 表6 Day176 の表の出し直し(40ワールド、乱数なし8本)===
真の差(対 lgb_det): 低雑音 leaf63 -3.67(16/16) leaf127 -3.50(15/16) leaf255 +0.97(6/16) leaf511 +9.13(0/16)
小得 leaf127 -22.96 leaf255 -25.60(12/12) leaf511 -17.20
中雑音 leaf127 -31.74 leaf255 -36.95(12/12) leaf511 -29.24
隣どうし: 255−127 低 +4.47 / 小得 -2.64 / 中 -5.21、511−255 低 +8.16 / 小得 +8.41 / 中 +7.72(いずれも全ワールドで同じ向き)
mcs50 の悪化: 15組(3世界×葉127/255/511)すべてで全ワールド悪化、+9.49〜+25.04
DET8 の真の最良: 低雑音 {leaf63: 8, leaf127: 8} 小得 {leaf255: 12} 中雑音 {leaf255: 12}
候補一覧の損(補正CV で選ぶ、対 DET8 の真の最良):
低雑音 小得 中雑音 最悪
L3 0.88 2.64 5.21 5.21
L4 0.88 0.66 0.31 0.88 (L5・L8・L4+止め方 も同じ値)
費用(1ワールド5fold、中央値秒): leaf127 28 / leaf255 52 / leaf511 114 / leaf127_m50 43 / leaf255_m50 87 / leaf511_m50 173
=== 表7 「引き分けなら小さい木」を決定15(L4)に足した損(40ワールド、×1e-4)===
引き分けの幅 = z × 対の SE(葉127 対 葉255 の対の SE は 3.2〜3.4)
z=0(今の決定15) 低 0.88 小得 0.66 中 0.31 最悪 0.88
z=0.5 低 1.43 小得 0.78 中 0.52 最悪 1.43
z=1 低 1.93 小得 1.43 中 1.73 最悪 1.93
z=2 低 3.43 小得 3.24 中 4.09 最悪 4.09
タスクC(戦略の模範)
- 決定13(補正CV)は葉511 まで ◎ に戻す。 Day176 の「効きすぎ」(低雑音 葉511 −4.78±1.76)は3ワールドの偶然で、40ワールドでは +3.15±1.96。21組(3世界×7本)の残りは最大でも 2.0SE(低雑音 leaf255_m50、21回検定すれば1回は出る大きさ)で、向きもそろわない(負の割合 0.31〜0.75)。Day176 の仮説(A の推定誤差)は外れ: 項2 は平均で最大 0.24、ワールド間 SD でも最大 0.70。恒等式から A の取り方そのものに偏りは無く、残るのは test 2万行の引き方だけで、それは A の 1% 台しか揺れない
- 残りの揺れは「OOF を採点する train 行の引き方」が作り、木が大きいほど育つ(SD 3.0→8.4)。 予測 SD(行ごとの差の SD から計算)は実測の 67〜92% を説明する。残り 8〜33% は分割の偶然で、表5 では分割 seed を変えると相関 0.34〜0.77 で同じ向きに残る。この揺れが選び間違いを生む(小得で葉127 を3/12回選んだ)。しかし「引き分けなら小さい木」は損を増やした(z=1 で最悪 0.88→1.93)。対の SE(3.2〜3.4)より真の差(中雑音 255−127 で −5.21)の方が大きく、小さい木へ寄せると取りこぼしの方が大きいため。決定15 には足さない
- 分割の繰り返しでは消えない部分が半分以上ある。 表5 の値から粗く分けると(6ワールドで精度は低い)、分割ごとの揺れ SD 3.0〜6.3 に対し、分割で変わらない共通部分 SD は √(2回平均の分散 − 分割の分散/2) ≒ 3.6〜5.0。分割を何回繰り返しても後者は残る。これを減らすのは採点に使う行を増やすこと(今の設計では train 行 30,000 が上限)。実データで効く手は、train の行を増やすことではなく(増やせない)、1回の比較の差が対の SE の何倍かを記録し、2SE 未満の勝ち負けを「決め手にならない」と書いておくこと
タスクD(決定)
| # | 決定 | 採った案 | 採らなかった案と理由 | 前提が変わったら |
|---|---|---|---|---|
| 13(印を戻す、◎) | 補正CV √(C²−A_test) を葉511 まで使う | 40ワールドで残り 21組すべて 2SE 以内、項2 は最大 0.24 | (a) 葉255 以上は ○ のまま: 根拠だった −4.78 は 3ワールドの偶然。(b) A を truth 側で測る: 実データには truth が無い | 切り詰め(予測 1 未満の clip)が多いデータ(目的変数が 0 付近に集まる)では項3 を測り直す。今日は最大 0.09 |
| 15(印 ○→◎、一覧 L4 を確定) | 乱数なしの葉 31/63/127/255 を補正CVで比べる。端(255)が最良なら 511 を1本足す | 40ワールドで最悪の損 0.88(L3 は 5.21)。L5・L8・止め方つきも同じ 0.88 | L8 を常に回す: 損は同じで1ワールド約 417 秒余分(葉511 114 秒+mcs50 の3本 43+87+173 秒、中央値) | 学習率・本数を変えたら山が動く(次回) |
| 16(新設、印 ○) | 「引き分けなら小さい木」は使わない(z=0) | z=0 が3世界とも最良(最悪 0.88) | z=1(最悪 1.93)、z=2(最悪 4.09): 真の差が対の SE より大きい世界では、寄せるほど取りこぼす | 真の差が対の SE より小さい(候補がほぼ同じ強さの)世界では、費用の安い方へ寄せる価値が出る。そのときは z と費用の両方で測り直す |
| 17(新設、印 △) | 比較の記録に「差 ÷ 対の SE」を添え、2SE 未満の勝ちは決め手にしない | 選び間違いの源は行の引き方で、分割を繰り返しても半分以上残る | 分割の繰り返し回数を増やして決める: 共通部分(SD 3.6〜5.0)は消えない | 実データで train 行が 1 桁多いなら対の SE は約 1/3 になり、この注意はほぼ不要 |
📊 結果の可視化
1枚目: 残りの揺れ(ワールド間 SD)は木が大きいほど育ち、その 67〜92% は「OOF を採点する train 行の引き方」だけで予測できる。残りは分割の偶然。2枚目: 揺れに合わせて小さい木へ寄せると、取りこぼしの方が大きく、最悪の損が増える。
🪜 Step-by-Step 解説
Step 1: 測る前に式で分ける
Day176 の仮説は「A の推定がずれる」。恒等式 T1 − T5² = A_truth を先に示すと、A が入るのは項2(行の違い)だけで、fold 数や木の大きさで偏りが生まれる余地が無いと分かる。仮説が式の段階で弱いと分かれば、測るべきは項1 になる。
Step 2: 恒等式を数値で確かめる
切り詰め無しで計算した差は最大 1.39×10⁻¹⁷。これで「項1+項2+項3=残り」が帳簿として閉じる(足し算の残差が無い)。
Step 3: 打ち切った31ワールドを回し、先に再現を確かめる
今日の leaf127 は raw175 と OOF・fold 別予測とも最大差 0.0。venv を作り直したので、ここが崩れていたら Day176 の9ワールドと混ぜられなかった(決定9)。
Step 4: 3世界 × 7本で3項を並べる
21組すべてで「残り ≒ 項1」。項2・項3 は 0.3 未満。Day176 の −4.78 は 3ワールドの平均で、16ワールドでは向きが逆(+3.15)になった。
Step 5: 項1 の揺れの出どころを予測と照合する
行ごとの二乗誤差の差の SD を √行数 で割れば、「行の引き方だけ」で出る SD が予測できる。予測は実測の 67〜92%。残りは分割の偶然。
Step 6: 分割を変えて確かめる(入れ子の罠に注意)
分割 seed 1 の5分割では相関 0.34〜0.77 で同じ向きに残る。10分割(seed 0)との相関 0.82〜0.98 は高すぎるので疑い、KFold の入れ子(同じ seed では 10 分割の fold が 5 分割の fold の半分)を確認して除外した。
Step 7: 揺れが分かったら、それで判断を変えるべきかを測る
「引き分けなら小さい木」は直感的に良さそうだが、測ると損が増えた。揺れを知ることと、揺れに合わせて選び方を変えることは別。
📐 数学・統計の補足(文系向け)
恒等式の直感。 5人に体重計の目盛りを読ませる。「5人それぞれの読み違いの二乗の平均」は、「5人の平均の読み違いの二乗」より必ず大きく、その差は5人の読みのばらつきとぴったり同じ。ばらつきの分だけ平均を取ると得をする。これは近似ではなく、平均の定義から出る足し算の事実(クロス項が 0 になる)。
だから A に偏りは無い。 補正CV が引いている A_test は、まさにこの「平均で得する分」を test 行で測ったもの。同じ5本のモデルなので、測る行が違う(test と truth)ことによる揺れしか入らない。2万行もあれば揺れは A の 1% 台。
残るのは「採点する行の運」。 生の CV は train 3万行で採点する。真は別の 6万行で採点する。同じモデルでも、たまたま当てやすい行が train に多ければ CV は良く見える。木が大きいほど行ごとの得意・不得意が lgb_det とずれるので(低雑音の Day176 の9ワールドで、行ごとの差の SD が 葉63 158 → 葉511 292、×10⁻⁴ 二乗)、この運の影響が大きくなる。
二乗の差を RMSLE の差に直す。 √x の傾きは 1/(2√x)。T5 が 0.16〜0.22 なので、二乗の世界の差を 2.3〜3.2 倍して RMSLE の差に直している。
🏆 Kaggleでの実践的な使い方
- fold 平均で提出するなら、候補比較は補正CV で。 生の CV は葉511 を最大 +42 悪く見せる(中雑音、Day176)。補正後の残りは 40ワールドで平均 0 付近
- CV の差が小さいときは「対の SE」を一緒に書く。 OOF 行ごとの二乗誤差の差の SD / √行数 を、2×CV で割れば RMSLE の差の SE になる。今日のデータでは葉127 対 葉255 で 3.2〜3.4×10⁻⁴。これより小さい勝ち負けは決め手にならない
- 分割 seed を何回変えても消えない誤差がある。 採点に使う train 行そのものの運で、今日のデータでは揺れの半分以上
- 「迷ったら小さいモデル」は常に正しくはない。 真の差が SE より大きい世界では損をする(今日は最悪の損が 2.2〜4.6 倍)
- 同じ seed で KFold の fold 数だけ変えた比較は独立ではない。 5分割と10分割が入れ子になる
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| fold 5個の分散は推定なので、大きい木ほどずれる | 「5個で分散を取る」が粗く見える | 5本平均の得は5本の分散(÷5)と恒等式で等しい。近似ではない |
| 3ワールドで 2.7SE なら本物の偏り | SE の数字だけを見る | 3個の SD は不安定で、21組を見れば1組は 2SE を超える。16ワールドで向きが逆転した |
| 分割 seed を増やせば CV の揺れは消える | 分割の偶然しか考えない | train 行の引き方による部分(今日は半分以上)は分割を変えても残る |
| 揺れが分かったら小さい木に寄せるべき | 「保守的=安全」 | 寄せると取りこぼしが増え、最悪の損が 0.88→1.93(z=1) |
| 同じ seed の 5 分割と 10 分割で相関が高いので再現性が高い | 入れ子を見落とす | 10 分割の各 fold は 5 分割の fold の半分。独立な比較ではない |
🧭 扱わなかった範囲と理由
- 独立な 10 分割(seed を変えた 10 分割): 今日の 10 分割は seed 0 で 5 分割と入れ子になり、独立な比較に使えなかった。fold 数の効果(偏りが生まれないこと)は恒等式で示したが、揺れの大きさを独立な分割で測るのは未計測
- 分割の比較の小得世界と、ワールド数: 低雑音・中雑音の各6ワールドのみ(費用 1,386 秒)。表5 の共通部分の SD は6ワールドからの粗い値
- 乱数ありの候補(決定14 の後段)を 40 ワールドで出し直すこと: 低雑音の保存物 raw172 が tmp の掃除で消えていた。中雑音・小得の raw173/174 は残っているが、3世界そろわないので今日は出さない
- 学習率・本数(lr 0.05・600 本)と mcs を下げる方向(5・10): 次回以降
- 実データ(S5E5): 縮小シミュレータの上の数字のみ。S5E5 のルール確認・公開割合・敵対的 AUC は Day171 で利用者の作業として切り出したまま
- 原典照合: LightGBM 公式ドキュメント(Parameters Tuning)・Nadeau & Bengio・Krogh & Vedelsby(アンサンブルの曖昧さ分解。今日の恒等式は回帰の二乗誤差でのその特殊な形)の原文は今日も照合していない
- 持ち越し: 候補数 K と選択の上振れ、系統別の m(
et)、公開LB と2本目の枠、avg3 での損、OOF 側と test 側の seed の揺れの分離、noKeytel・raw7の補正後のずれ、補正CV と入れ子CV の比較、Day170 のハイブリッド・狭い10本の出し直し、SE 個数差と分割の新しさ(Day165)、Day162 の選択バイアス、真の効果ちょうど0の偽採用率
🚀 次のステップ
- 発展: seed を変えた独立な 10 分割(例: seed 2)で、表5 の「分割ごとの揺れ」が fold 数でどう変わるかを測る
- 発展: 対の SE を実データの比較記録に入れる書式(決定17)を、CV設計書(Day171)に1行足す
- 次回予告: Day 178 — Playground Series 実戦投入⑬(学習率 0.05・600本で葉 63/127/255/511 を作り、山の位置が動くか。決定15 の一覧と「端なら1本足す」止め方が学習率を変えても持つかを測る)。月替わりテーマ3「画像(CV)系コンペへの応用」は 10/25 から
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: