📚 背景知識(読んでから問題へ)
Kaggle の最終提出の規則(今日のモデル)。 コンペの終わりに、自分の提出の中から最大2本を選ぶ。順位は、選んだ2本のうち非公開(private)LB で良い方で決まる。公開(public)LB は test の一部(Playground Series ではおおむね 20%)で、締め切りまで見える。非公開は残り(80%)で、締め切り後にしか見えない。
ここで大事なのは、2本目は損をしないということ。2本のうち良い方が数えられるので、2本目が1本目より悪くても順位は下がらない。問いは「2本目にどれを入れると一番得か」だけになる。
今日の前の決め方(CV設計書の該当部分)。
| 決定 | 中身 | 印(今日の前) |
|---|---|---|
| 8 | HistGB に knn を 0.10 混ぜる | ○(LightGBM の上では未計測) |
| 12 | 最終2本: 1本目=決定20 の1本。2本目は未定 | △ |
| 13 | 候補は補正CV √(C² − A_test) で比べる | ◎(葉・固定本数)/✕(早期打ち切り) |
| 20 | 決定15 の葉を lr0.05・1,200本で1回学習し、600〜1,200本から補正CV 最小 | ○ |
Day170〜171 で「CV最良+公開LB最良」の2枠を測ったが、そのときの候補は HistGB の設定違いで、1本目は今より 2〜3×10⁻⁴ 弱かった。決定20 の1本は強くなったので、「2本目に公開LB を使う得」が残っているかは分からない。
今日の作り方。 Day181 と1文字も同じ生成器(ワールドの乱数 3000+番号、40ワールド=低雑音16・小得12・中雑音12)で、lr0.05・1,200本の乱数なし LightGBM 葉 31/63/127/255 と、Day166 と同じ k近傍(15近傍・標準化・5列)を5 fold で作る。そこから提出候補 182本を作る:
| 種類 | 本数 | 中身 |
|---|---|---|
| 単体 | 52 | 葉4種 × 本数13点(600, 650, …, 1,200) |
| knn 混ぜ | 52 | 単体 × 0.9 + knn × 0.1(決定8 の重み、log 空間で fold ごとに混ぜる) |
| 葉ペア混ぜ | 78 | 葉の6組(31+63, …, 127+255)× 同じ本数13点、50/50 |
各候補について、OOF(30,000行)から生CV と補正CV、truth(60,000行)から真の誤差 T5、test(20,000行)から公開/非公開の点数を作る。test を公開/非公開に500回ランダムに分け直し、2本目の方針ごとに「非公開で良い方」の点数を出す。
用語整理:
| 用語 | 意味 |
|---|---|
| 1本目 | 今日の基準は決定20(決定15 の葉、600〜1,200本から補正CV 最小の単体) |
| 公開LB最良 | 公開の行だけで測った RMSLE が最小の候補(1本目と同じなら2位) |
| 非公開の損 | 2本のうち非公開で良い方の RMSLE − その再分割での182本の非公開最良(再分割500回の平均) |
| 真の誤差の差 | 非公開で勝った方の T5(truth 6万行)を比べる。非公開の雑音の運を除いた差 |
| 対の差 | 同じワールドで2つの方針の値の差を取り、ワールドについて平均±SE |
数値はすべて縮小シミュレータの上の実測(S5E5 の構造を写した合成データ、Day163〜)。実データ(Kaggle Playground S5E5)では測っていない。
データ・保存物の構造(スキーマ)
| 名前 | 形・型 | 意味・作り方 | 使う場所 |
|---|---|---|---|
| Sex … Body_Temp, Dur_x_HR, Keytel_kcal, log_Dur | int / float | Day163〜181 と同じ合成(ワールドの乱数 3000+番号)。低雑音16・小得12・中雑音12。train 3万・元1.5万・test 2万・truth 6万 | 全候補 |
| oof5 | (4, 13, 30000) float32 | lr0.05 の葉31〜255 × 本数13点(600〜1,200)の OOF(log) | 生CV・補正CV |
| oofk / tstk | (30000) / (20000) float32 | k近傍(15近傍・標準化・5列)の OOF と test の5本平均 | knn 混ぜ |
| tst | (4, 13, 20000) float32 | test の5本平均(丸め前の log)。混ぜは線形なので集計側で作る | 公開/非公開の再分割 |
| S5 / SK / SP | (4,13,4) / (4,13,4) / (6,13,4) | 単体・knn 混ぜ・葉ペア混ぜの T5²・T1²・A_test・A_truth(fold ごとに混ぜてから集計) | 補正CV・真の誤差 |
| yte | (20000) int | test のラベル(シミュレータなので持てる) | 公開/非公開の点数 |
| 保存先 | work/d182/r/{low,sm,mid}/raw182_w*.npz(計 350MB)・d182.pkl | tmp の外 | 次回以降 |
評価指標(RMSLE)と、最終2本の数え方
RMSLE は log1p 空間の RMSE(小さいほど良い)。差はすべて ×10⁻⁴。最終順位は「選んだ2本のうち非公開で良い方」。だから2本目は損をしえず、問いは「どれを入れると一番得か」だけになる。下の図は、2本目を測る前に見つかった「1本目の負け」。
❓ 問題
タスクA(予想を先に書く)
測る前に、次の4つに「当たる/外れる」と理由を書く。
- 1本目(決定20 の単体)は、候補182本の中でも真の最良に近い(損 1×10⁻⁴ 以下)
- 2本目に公開LB最良(182本から)を入れると、候補数が多いので公開LB に合わせすぎ、補正CV 2位を入れるより損をする
- 公開割合が小さい(5%)ほど、2本目に公開LB を使う得は消える
- knn 0.1 混ぜ(決定8)は、強くなった LightGBM の上ではもう得が無い
タスクB(コーディング)
day181.pyの生成部を1文字も変えずに、葉31〜255(600〜1,200本の13点)と k近傍の OOF・test 予測・truth 集計を作り、混ぜた候補は fold ごとに混ぜてから集計するday182.pyを書く- 600〜1,200本の OOF と truth 集計が Day181 の保存物と一致することを確かめる(再現)
analyze182.pyで、公開 5/20/50% × 再分割500回 の上で、2本目の方針ごとの非公開の損・真の誤差・2本目が勝つ割合を出す
タスクC(分析と決定)
- 2本目には何を入れるか。公開LB を使うか、補正CV の2位か、混ぜか
- 1本目は決定20 のままでよいか
- 「2本目の得」のうち、本当に良いモデルを拾った分と、非公開の雑音の運の分を分ける
💡 ヒント
ヒント1(方向性)
「2本のうち良い方」は、2本の非公開の点数の最小値。2本の真の強さが同じでも、非公開の雑音がばらばらなら最小値は平均より下がる。だから、2本目の得は「真に良い候補を拾った」分と「雑音の運」の分に分けて見る(真の誤差 T5 と非公開の点数の両方を出す)。
ヒント2(アプローチ)
公開/非公開の再分割は、学習し直さなくてよい。候補ごとに test 2万行の二乗誤差 e[行, 候補] を1回だけ作り、公開に選んだ行の和と全体の和の差から非公開を出す。混ぜた候補の OOF と test 予測は log 空間で線形なので、保存した単体と knn から集計側で作れる。truth の集計(A_test を含む)だけは fold ごとの予測が要るので、学習側で混ぜてから取る。
ヒント3(コード骨格)
tot = e.sum(0) # e: (20000, 182) test の二乗対数誤差 for s in range(500): pub = rng.choice(20000, npub, replace=False) P = e[pub].mean(0); Q = np.sqrt((tot - e[pub].sum(0)) / (20000 - npub)) # 公開 MSE・非公開 RMSLE second = [c for c in np.argsort(P) if c != first][0] # 公開LB最良(1本目と同じなら2位) loss = min(Q[first], Q[second]) - Q.min() # 2本のうち良い方 − 182本の非公開最良
✅ 模範解答
タスクA(判定)
- 外れ(今日一番大きい外れ)。 決定20 の1本の真の損(182本の真の最良との差)は 低雑音 4.69・小得 5.93・中雑音 5.59(×10⁻⁴)。真の最良は 40/40 で混ぜた候補(葉ペア 31、knn 混ぜ 9)で、29/40 が
s31+s255(一番小さい木と一番大きい木の 50/50) - 後半(補正CV 2位より損)は外れ、前半(合わせすぎ)は小さく当たり。 公開20% で、決定20 の後ろに公開LB最良(182本)を置くと非公開の損 −4.17±0.25、補正CV 2位の葉を置くと −1.08±0.18。1本目を混ぜに替えたあとでも、2本目は公開LB最良が補正CV 2位より −0.21±0.09 良い。ただし候補を狭い6本に絞った公開最良は、広い182本より −0.22±0.10(公開20%)、−0.36±0.08(公開5%)良く、候補が多いほど公開LB に合わせすぎる害はある(2本目は損をしない規則なので、害は「得が減る」形で出る)
- 当たり(向きは)。 1本目を補正CV 最良(182本)にしたあとの2本目の得は、公開 5% で −0.16±0.04、20% で −0.31±0.09、50% で −0.49±0.13。小さくなるが、5% でも 0 にはならない(2本目は損をしないので、得が小さくなるだけ)
- 外れ。 決定20 の1本に knn を 0.1 混ぜると真の誤差 −3.23±0.27(40/40 で良い)。低雑音 −1.49±0.17、小得 −4.03±0.26、中雑音 −4.75±0.29。Day166 の HistGB の上(−0.6、4ワールド中2つで得)より大きい
タスクB(完全なコード)
day182.py(生成部 keytel_rate・make_original・synth_from・add_feats・BASE は Day181 と1文字も同じなので省略。全文は work/d182/day182.py):
KNN = ["log_Dur", "Heart_Rate", "Weight", "Age", "Sex"] # Day166 の k近傍の列 I0 = IT.index(600); IS = IT[I0:]; nS = len(IS) # 保存は 600..1200 の13点 PAIRS = [(a, b) for a in range(nM) for b in range(a + 1, nM)] # 葉ペア 6組 WK = 0.10 # 決定8 の knn の重み for k, (tr, va) in enumerate(KFold(5, shuffle=True, random_state=0).split(train)): tr_df = pd.concat([train.iloc[tr], orig], ignore_index=True) X, y, XV = tr_df[BASE].values, np.log1p(tr_df.Calories.values), train.iloc[va][BASE].values for j, L in enumerate(LEAVES): m = lgb.LGBMRegressor(**LG5, num_leaves=L, random_state=k).fit(X, y) # eval_set は木を変えないので外した sv, se_ = np.zeros(len(va)), np.zeros(len(XE)); a = 0 for i, b in enumerate(IT): # 塊ごとに足す(Day179〜) sv += m.predict(XV, start_iteration=a, num_iteration=b - a, raw_score=True) se_ += m.predict(XE, start_iteration=a, num_iteration=b - a, raw_score=True) if i >= I0: oof5[j, i - I0, va] = sv; ev5[j, i - I0, k] = se_ a = b sc = StandardScaler().fit(tr_df[KNN]) kn = KNeighborsRegressor(n_neighbors=15, algorithm="kd_tree").fit(sc.transform(tr_df[KNN]), y) oofk[va] = kn.predict(sc.transform(train.iloc[va][KNN])); evk[k] = kn.predict(sc.transform(evalset[KNN])) E = ev5.astype(np.float64) S5 = np.array([[agg(E[j, i]) for i in range(nS)] for j in range(nM)]) # 単体 SK = np.array([[agg((1 - WK) * E[j, i] + WK * evk) for i in range(nS)] for j in range(nM)]) # knn 混ぜ(fold ごとに混ぜる) SP = np.array([[agg(0.5 * E[a, i] + 0.5 * E[b, i]) for i in range(nS)] for a, b in PAIRS]) # 葉ペア tst = E[:, :, :, :N_TEST].mean(2) # test の5本平均(丸め前)。公開/非公開は集計側で
analyze182.py の方針部分(全文は work/d182/analyze182.py):
Ca = np.sqrt(c2 - S[:, 2]); T5 = np.sqrt(S[:, 0]) # 182本の補正CV と真 best_leaf = {j: 単体のうち葉 j で補正CV 最小 for j in range(4)} first = best_leaf[葉 L15] # 決定20 p3 = min(他の3葉の best_leaf, key=Ca) # 補正CV 2位の葉 p4 = first の knn 混ぜ; p5 = 葉ペアの補正CV 最良; p6 = 182本の補正CV 2位 narrow = 4葉の best_leaf + [p4, p5] # 狭い6本 for split in 500 回: pw = 公開最良(182本, first を除く); pn = 公開最良(narrow, first を除く) g = pn if 公開で (pn − first) の対の差 < −2SE else p3 # ガード案 f2 = argmin(Ca) # 1本目も替える案 sec = [(first, c) for c in [first, pw, pn, p3, p4, p5, p6, g]] + [(f2, f2), (f2, 公開最良), (f2, 補正CV 2位)] loss = min(Q[a], Q[c]) - Q.min(); 勝った方の T5 も記録
run.sh と実行:
# run.sh: 1ワールドを1スレッドで作る。venv は Day180 のもの(work/d180/.venv)、sklearn 同梱の libomp を渡す V=../d180/.venv export OMP_NUM_THREADS=1 DYLD_LIBRARY_PATH="$V/lib/python3.13/site-packages/sklearn/.dylibs" $V/bin/python day182.py "$1" "$2" "$3" "r/$4" > "log/$4_w$1.log" 2>&1 # 40ワールドを14並行(ジョブ一覧は Day181 の jobs_o.txt をそのまま使う) xargs -P 14 -L 1 ./run.sh < jobs.txt # 集計(決定15 の葉は Day180 の d180.pkl、再現の照合は Day181 の raw181) ../d180/.venv/bin/python -W ignore analyze182.py r ../d180 ../d181 > a40.txt ../d180/.venv/bin/python -W ignore extra182.py > extra182.txt
実行結果(実測)
# ============ 実行環境: macOS・Apple M5 Pro(15コア・48GB)・uv venv(Python 3.13.16・lightgbm 4.7.0・scikit-learn 1.9.1・
# numpy 2.5.4・pandas 3.0.6、Day180 と同じ venv)。OMP_NUM_THREADS=1・n_jobs=1、14並行
# 40ワールド × (葉4種 + knn) × 5 fold = 1,000 fit(LightGBM 800 は各1,200本)
# 壁時計 6分45秒(04:13:51→04:20:36)、1ワールド 121〜144秒。保存物 r/{low,sm,mid}/raw182_w*.npz 計 350MB(work/d182)
# 集計 59秒(182本 × 再分割500回 × 公開割合3通り × 40ワールド)
ワールド数: {'中雑音': 12, '低雑音': 16, '小得': 12} 再分割 500 回 × 公開割合 [0.05, 0.2, 0.5]
=== 表0 再現: 600..1200本の13点を Day181 の raw181 と比べる(最大絶対差、40ワールド)===
OOF: 0.0e+00 S5: 0.0e+00 ← eval_set を外しても木は同じ(完全一致)
=== 表1 公開 20%: 非公開の損(2本のうち良い方 − 182本の非公開最良、×1e-4)と「1本だけ」との対の差(良/悪ワールド数)===
2本目の方針 低雑音 小得 中雑音 40ワールド 対の差 (z) 最悪 2本目の勝率
1本だけ(決定20 のみ) 5.21 6.81 5.88 — 6.81 —
公開LB最良(広い182本) 2.02 (-3.19±0.31) 16/0 1.56 (-5.25±0.42) 12/0 1.48 (-4.40±0.42) 12/0 -4.17±0.25 (-16.4) 2.02 0.93
公開LB最良(狭い6本) 1.82 (-3.39±0.35) 16/0 1.33 (-5.48±0.58) 12/0 1.24 (-4.64±0.41) 12/0 -4.39±0.29 (-15.4) 1.82 0.94
補正CV 2位の葉 4.29 (-0.92±0.25) 12/0 5.20 (-1.62±0.39) 10/0 5.13 (-0.75±0.25) 11/0 -1.08±0.18 (-6.1) 5.20 0.61
knn 0.1 混ぜ(決定8) 3.67 (-1.54±0.28) 16/0 3.01 (-3.81±0.46) 12/0 1.40 (-4.48±0.49) 12/0 -3.10±0.31 (-10.1) 3.67 0.94
葉ペア混ぜの補正CV最良 0.69 (-4.52±0.37) 16/0 0.64 (-6.18±0.63) 12/0 0.95 (-4.93±0.40) 12/0 -5.14±0.28 (-18.2) 0.95 1.00
補正CV 2位(182本全体) 0.87 (-4.34±0.41) 16/0 1.18 (-5.63±0.56) 12/0 0.82 (-5.06±0.41) 12/0 -4.95±0.27 (-18.2) 1.18 1.00
ガード: 狭い6本の公開最良が −2SE なら採用 3.47 (-1.74±0.27) 16/0 2.63 (-4.18±0.58) 12/0 2.79 (-3.09±0.47) 12/0 -2.88±0.29 (-9.9) 3.47 0.78
[1本目も替える] 補正CV最良(182本)のみ 0.87 (-4.34±0.41) 16/0 1.18 (-5.63±0.56) 12/0 0.82 (-5.06±0.41) 12/0 -4.94±0.27 (-18.2) 1.18 —
[1本目も替える] 補正CV最良+公開LB最良 0.63 (-4.58±0.38) 16/0 0.62 (-6.19±0.47) 12/0 0.67 (-5.21±0.41) 12/0 -5.25±0.26 (-20.3) 0.67 0.32
[1本目も替える] 補正CV 1位+2位 0.83 (-4.38±0.41) 16/0 1.14 (-5.67±0.55) 12/0 0.59 (-5.29±0.39) 12/0 -5.04±0.27 (-18.7) 1.14 0.41
(「悪」が全部 0 なのは、2本目は良い方だけ数える規則なので損をしえないから)
=== 表2 公開割合を変える: 1本目=補正CV最良(182本) の上で2本目を足す得(×1e-4、非公開の損の対の差 / 真の誤差の対の差)===
公開割合 +公開LB最良 +補正CV 2位 公開LB最良 − 補正CV 2位
5% -0.16±0.04 (34/0) / -0.04±0.03 -0.09±0.03 (23/0) / -0.01±0.02 -0.06±0.05 / -0.03±0.04
20% -0.31±0.09 (35/0) / -0.12±0.06 -0.10±0.03 (31/0) / -0.01±0.02 -0.21±0.09 / -0.12±0.07
50% -0.49±0.13 (40/0) / -0.19±0.08 -0.12±0.04 (39/0) / -0.00±0.02 -0.37±0.13 / -0.19±0.09
(決定20 を1本目のまま、狭い6本の公開最良 − 広い182本の公開最良: 5% -0.36±0.08 / 20% -0.22±0.10 / 50% -0.12±0.12。
決定20 を1本目のまま、2本目を公開LB最良(182本) にした場合: 5% -3.01±0.22 / 20% -4.17±0.25 / 50% -4.76±0.27。
真の誤差では -2.71±0.21 / -3.94±0.22 / -4.48±0.22。補正CV 2位の葉: 非公開 -1.08±0.18 に対し真 -0.30±0.19)
=== 表3 公開20%: 2本目に選ばれた候補の種類(再分割×ワールドの割合)===
公開LB最良(広い182本): 葉ペア 0.58, knn混ぜ 0.40, 単体 0.02
公開LB最良(狭い6本): 葉ペア 0.63, knn混ぜ 0.27, 単体 0.09
ガード案: 単体 0.55, 葉ペア 0.29, knn混ぜ 0.16
=== 表4 決定8 を決定20 の1本の上で: knn 0.1 混ぜ − 決定20(真の誤差、×1e-4)と補正CV の対の偏り ===
[低雑音] 真の差 -1.49±0.17(良/悪 16/0) 補正CV の対の偏り +0.15±0.25
[小得] 真の差 -4.03±0.26(良/悪 12/0) 補正CV の対の偏り +0.27±0.32
[中雑音] 真の差 -4.75±0.29(良/悪 12/0) 補正CV の対の偏り +0.22±0.37
[40ワールド] 真の差 -3.23±0.27 偏り +0.21±0.17
=== 表5 1本目を替える: 補正CV最良(182本)− 決定20(真の誤差、×1e-4)===
[低雑音] -4.20±0.29(16/0) 真の最良との差 決定20 4.69 → 0.49 選ばれた種類 葉ペア 15・knn混ぜ 1
[小得] -5.13±0.33(12/0) 真の最良との差 決定20 5.93 → 0.80 選ばれた種類 葉ペア 8・knn混ぜ 4
[中雑音] -4.80±0.23(12/0) 真の最良との差 決定20 5.59 → 0.79 選ばれた種類 knn混ぜ 8・葉ペア 4
[40ワールド] -4.66±0.17(40/40、z -27)。補正CV最良の真の損の最大 2.77
真の最良の種類: 低雑音 葉ペア 16/16、小得 葉ペア 11・knn混ぜ 1、中雑音 knn混ぜ 8・葉ペア 4。s31+s255 が 29/40
補正CV最良に選ばれた候補: s31+s255 20, s255+knn 9, s31+s127 5, s127+knn 3, s63+s255 2, s63+knn 1
=== 表6 費用(1ワールド5fold、中央値秒。学習1,200本+13点の予測)===
葉31 12.3 / 葉63 18.4 / 葉127 31.9 / 葉255 63.7 / knn 3.1 → 4葉+knn で計 129秒、決定20 の1葉だけなら 18〜64秒
タスクC(分析と決定の模範)
- 1本目を替える(決定22 を新設、◎)。 2本目を決める前に、表5 で1本目が負けていた。候補182本から補正CV 最良を1本目にすると、決定20 より真の誤差 −4.66±0.17(40/40、z −27)、真の最良との差は 4.7〜5.9 → 0.5〜0.8。Day181 で「葉も本数も補正CV(4葉)」を「差 −0.04 に4倍の費用」で採らなかったが、それは単体どうしを比べたからで、4葉を作れば混ぜが作れる。4葉を作る費用(1ワールド 126秒、決定20 の1葉の2〜7倍)は、−4.66 の得に対して払う
- 2本目は公開LB最良(182本、1本目と同じなら2位)にする(決定12 を改訂、○)。 1本目を決定22 にした上で、公開20% の得は −0.31±0.09(35/0)、補正CV 2位より −0.21±0.09。公開割合 5% でも −0.16±0.04 で損はしない。ガード案(公開で −2SE 勝ったときだけ公開最良)は、決定20 の上で −2.88±0.29 と、素直な公開最良(−4.39±0.29)より悪い。2本目は損をしえないので、慎重にする理由がない
- 2本目の得の6割強は運(決定12 に注記)。 公開20% で非公開の得 −0.31 のうち、真の誤差で残るのは −0.12±0.06。残りは「2本の非公開の雑音のうち良い方を取れる」得で、順位には効くが、モデルが良くなったわけではない。補正CV 2位の葉はもっと極端で、非公開 −1.08±0.18 に対し真 −0.30±0.19(2SE 未満)。2本目の評価を非公開の点数だけで書くと、雑音の運をモデルの力と読み違える
- 決定8 は LightGBM の上でも得(◎に格上げ)。 knn 0.1 混ぜは 40/40 で真の誤差が良く、−3.23±0.27。補正CV の対の偏り +0.21±0.17(2SE 未満)なので、混ぜた候補も補正CV で比べてよい(決定13 に追記、○)
タスクC-4(CV設計書の差分、2026-10-15 版)
決定1〜21 のうち、今日変えた行だけを書く(他は Day181 の表のまま)。
| # | 項目 | 今の決め方 | 印 | 根拠(測った数字) | 前提が変わったら |
|---|---|---|---|---|---|
| 8 | 混ぜる(knn) | 決定20 の葉に knn 0.1 を混ぜた候補を、決定22 の候補に入れる | ◎(○から) | 決定20 の上で −3.23±0.27、40/40(今日) | 重み 0.1 は Day166 の HistGB で決めた値。LightGBM の上で重みを測り直していない |
| 12 | 最終2本 | 1本目=決定22、2本目=公開LB最良(182本、1本目と同じなら2位)。公開割合で切り替えない | ○(△から) | 2本目の得 −0.31±0.09(公開20%、35/0)、5% でも −0.16±0.04。うち真の誤差で残るのは −0.12±0.06。決定20 の上では狭い6本の公開最良が広い182本より −0.22±0.10 良かった | 決定22 の上で狭い6本と比べる。候補が10倍(2,000本)になったら公開最良の合わせすぎを測り直す |
| 13 | CV の直し方 | 補正CV で比べる。葉・本数・混ぜ(knn) の比較に使える。早期打ち切りには使えない | ◎/○(混ぜ)/✕(早期打ち切り) | knn 混ぜ 対 単体の偏り +0.21±0.17(今日) | 葉ペア混ぜの偏りは単独では測っていない |
| 20 | 作り直しの1本 | 1本目から外し、候補作りの部品にする(葉ごとの本数の範囲 600〜1,200 はそのまま) | ○(役割を変更) | 単体の1本目は決定22 より真で +4.66±0.17 | — |
| 22(新設) | 1本目 | 葉 31/63/127/255 を lr0.05・1,200本で1回ずつ学習し、単体52・knn 0.1 混ぜ52・葉ペア 50/50 混ぜ78 の182本から補正CV 最小 | ◎ | 対 決定20 −4.66±0.17(40/40、z −27)、真の最良との差 0.49〜0.80、最大 2.77 | 混ぜの重みを OOF で最適化する案は未計測(選択の上振れが増える)。葉511 が要る世界では候補に足す |
タスクD(今日の決定の記録)
| # | 決定 | 採った案 | 採らなかった案と理由 | 前提が変わったら |
|---|---|---|---|---|
| 22(新設、◎) | 1本目は182本から補正CV 最小 | −4.66±0.17、3世界とも 4SE 超 | (a) 決定20 の単体のまま: 40/40 で負ける。(b) 2本目に混ぜを入れて1本目は単体のまま(「葉ペア混ぜの補正CV最良」を2本目に): 非公開 −5.14±0.28 で近いが、1本しか出せない場面(2本目を公開LB に使いたい)で得を失う。(c) 混ぜの重みも OOF で最適化: 候補が連続になり、補正CV の選択の上振れが測れていない | 提出が1本しか選べないコンペでも同じ(1本目だけの得が −4.66 で、2本目の得 −0.31 より1桁大きい) |
| 12(改訂、○) | 2本目は公開LB最良(182本) | 公開20% で −0.31±0.09、補正CV 2位より −0.21±0.09 | (a) 補正CV 2位: 真の誤差の得がほぼ0(−0.01±0.02)。1位と似た候補を選ぶので保険にならない。(b) 狭い6本の公開最良: 決定20 の上では広い182本より −0.22±0.10(20%)・−0.36±0.08(5%)良いが、1本目を決定22 にした上では測っていない(持ち越し)。今日は測った方(広い182本)を採り、狭い6本は次回 決定22 の上で比べる。(c) ガード(−2SE): −2.88 対 −4.39 で悪い。2本目は損をしないので、慎重さが得を消すだけ | 公開割合が 5% 以下なら得は −0.16 まで縮むが、損はしないので変えない。2本目にも費用がかかる規則(提出数の上限が厳しい)なら見直す |
| 8(◎に格上げ) | knn 0.1 混ぜを候補に入れる | 40/40 で −3.23±0.27 | knn を外す: 中雑音では真の最良の 8/12 が knn 混ぜ | — |
| 20(役割変更) | 単体の作り直しは部品にする | 決定22 の候補の一部として残る | 廃止: 単体の本数選び(600〜1,200)は混ぜの部品の質に効く | — |
📊 結果の可視化
1枚目: 2本目の得の大半は「混ぜた候補を拾えたか」で決まり、単体の補正CV 2位は −1.08 しか得をしない。2枚目: 1本目を決定22 にした後の2本目の得は −0.16〜−0.49 で、真の誤差で残るのはそのうち 25〜39%。
🪜 Step-by-Step 解説
Step 1: 再現を先に確かめる
Day181 は学習のときに eval_set(val の誤差の記録)を付けていた。今日は外した。eval_set は誤差を記録するだけで木は変えないはずで、40ワールドの OOF と truth 集計が Day181 と完全一致(差 0.0)した。これで「Day181 と同じモデルの上に候補を足した」と言える。
Step 2: 2本目を測る前に、1本目を候補全体の中に置く(表5)
2本目の問いを立てる前に、182本の真の最良と1本目の差を見た。決定20 の1本は 4.7〜5.9 も負けていた。単体どうしの比較(Day181)では見えなかった差で、何と比べたかで「最良」の意味が変わる。
Step 3: 2本目の方針を並べる(表1)
決定20 を1本目に置いたままだと、2本目の得の大半は「混ぜた候補を拾えたか」で決まる。公開LB最良・葉ペア混ぜ・補正CV 2位(182本)はどれも混ぜを拾い −4.2〜−5.1、補正CV 2位の葉(単体)は拾えず −1.08。2本目の問いが、実は1本目の問いだったと分かる。
Step 4: 1本目を替えてから、2本目の得を測り直す(表2)
1本目を補正CV 最良(182本)にすると、2本目の得は −0.31(公開20%)まで縮む。公開LB最良が補正CV 2位より良い(−0.21±0.09)。
Step 5: 得を「良いモデル」と「運」に分ける(表2の右)
非公開の得 −0.31 のうち、勝った方の真の誤差の差は −0.12±0.06。残りは2本の非公開の雑音のうち良い方を取る得。補正CV 2位は真の得がほぼ0(−0.01±0.02)で、得のほぼ全部が運。
📐 数学・統計の補足(文系向け)
なぜ2本目は損をしないのか。 テストを2回受けて、良い方の点だけが成績になる、と同じ。2回目が悪くても1回目の点が残る。だから2回目は「当たれば得、外れても損なし」のくじになる。
なぜ同じ強さの2本でも得をするのか。 2本の真の実力が同じでも、非公開の 16,000行の上では、それぞれ偶然に少し良かったり悪かったりする。良い方を取ると、偶然の上振れの分だけ得をする。これが表2 の「非公開の得」と「真の得」の差(−0.31 対 −0.12)。順位には効くが、次のコンペで再現する実力ではない。
なぜ小さい木と大きい木を混ぜると強いのか。 葉31 の木は大まかな形を、葉255 の木は細かい形をつかむ。間違え方が違う2つを平均すると、間違いが打ち消し合う(Day166 で knn が Ridge より効いたのと同じ理由: 残差の相関が低い相手ほど混ぜる得が大きい)。似た葉どうし(127+255)より、遠い葉どうし(31+255)が 29/40 で真の最良になった。
🏆 Kaggleでの実践的な使い方
- 最終2本を選ぶ前に、1本目が候補全体で最良かを確かめる。 単体モデルの調整を続けた後は、手元の単体を混ぜた候補が一番強いことが多い。今日は混ぜるだけで −4.66×10⁻⁴(Day181 の本数選びの得 −0.96 の約5倍)
- 2本目は公開LB最良を素直に入れる。 2本目は損をしないので、「公開LB は当てにならない」は2本目を空ける理由にならない。ガード(公開で有意に勝ったときだけ)は得を減らした。ただし公開LB で選ぶ候補の数は絞った方が得(決定20 の上で、6本から選ぶと182本から選ぶより −0.22±0.10)
- 2本目の得を、非公開の点数で報告しない。 得の6割強は雑音の運。手法の比較には truth(実データなら、取れるなら後日の公開分割の入れ替えや別コンペ)で見る
- 公開ノートブックでよく見る「CV 最良+公開LB 最良」は、今日の結果では正しい形。 ただし「CV 最良」は混ぜを含む候補全体で、補正CV で選ぶ
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| 2本目は保険なので、1本目と似た安全な候補にする | 「保険」の言葉から外れにくい物を選ぶ | 似た候補は非公開でも似た点数で、良い方を取る得がほぼ無い(補正CV 2位の真の得 −0.01±0.02) |
| 公開LB は合わせすぎるので、2本目にも使わない | 公開LB 最良を1本だけ出すと危ないという話と混同 | 2本目は損をしない。公開20% で −0.31±0.09、5% でも −0.16±0.04 |
| 2本目の得は手法の良さ | 非公開の点数が良くなる | 得の6割強は、2本の非公開の雑音のうち良い方を取った運 |
| 単体の調整を詰めれば、その1本が最良 | 単体どうしで比べ続けた | 葉ペア混ぜ・knn 混ぜが 40/40 で上回る(−4.66) |
| 強い木には knn を混ぜても効かない | 弱いモデルを混ぜると薄まると思う | 決定20 の上でも −3.23±0.27。強さより間違え方の違いが効く |
| 似た葉どうしを混ぜるのが安全 | 点数が近いもの同士なら崩れない | 真の最良は遠い葉どうしの s31+s255 が 29/40 |
🧭 扱わなかった範囲と理由
- 混ぜの重みの最適化: 葉ペアは 50/50、knn は 0.1 に固定した。重みを OOF で最適化すると候補が連続になり、補正CV の選択の上振れ(Day170 の候補数 K の問題)が測れていないため。3つ以上の混ぜ(葉3種、葉ペア+knn)も作っていない
- 葉ペアの本数を別々に選ぶ: 今日は2つの葉を同じ本数で混ぜた(葉255 の山 650本と葉31 の山 1,200本以上は合っていない)。別々にすると候補が 13×13 倍になる
- 葉ペア混ぜの補正CV の偏り: knn 混ぜは測った(+0.21±0.17)が、葉ペアは単体との対の偏りを単独で出していない。補正CV最良の真の損が 0.49〜0.80 に収まっているので大きくはないと見たが、未計測
- 公開/非公開が合成データと同じ分布という前提: 再分割はランダム。実コンペで公開と非公開に偏りがある(時期で分ける等)場合は測っていない
- 2本目の候補の絞り方(決定22 の上): 狭い6本と広い182本の比較は決定20 を1本目にした場合だけ測った。決定22 の上では広い182本だけ
- 葉511: 決定15 が選ぶ世界が無いので作っていない
- 持ち越し: 1,200本より先、早期打ち切りの本数を入れ子で決める案、早期打ち切り×係数、学習率 0.02 以下、50〜150本での補正CV の偏り、seed を変えた独立な10分割、mcs 5・10、乱数ありの候補(決定14)、候補数 K と選択の上振れ(今日 182本でも1本目の真の損 0.49〜0.80、最大 2.77)、系統別の m(et)、avg3、OOF側とtest側の seed の揺れ、noKeytel・raw7、入れ子CV との比較、Day170 の出し直し、Day165 の SE 個数差、Day162 の選択バイアス、真の効果0の偽採用率
- 原典照合: 最終提出の規則(2本を選び、非公開で良い方が数える)は Kaggle の一般的な規則として記憶に基づく。S5E5 のルールページは今日照合していない。Nadeau & Bengio・Krogh & Vedelsby・LightGBM の文書も未照合
- 実データ(S5E5): 縮小シミュレータの上の数字のみ。Kaggle のログインとルール同意が要るので、利用者の作業として残す
🚀 次のステップ
- 発展: 葉ペアの本数を別々に選び、重みを 0.3/0.5/0.7 の3点だけ足して、候補が増えたときの補正CV の上振れ(候補数 K)を測る
- 発展: 混ぜた1本目(決定22)の上で、knn の重みを 0.05/0.10/0.15 で測り直す
- 次回予告: Day 183 — Playground Series 実戦投入⑱(決定22 の混ぜの広げ方: 葉ペアの本数を別々に・重み3点・3つ混ぜで候補を数百〜数千本にし、補正CV 最良の真の損が候補数でどう増えるかを40ワールドで測る)。月替わりテーマ3「画像(CV)系コンペへの応用」は 10/25 から
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: