Day 182 — 2026-10-15 | Playground Series 実戦投入⑰ — 最終2本の2本目を測りに行ったら、先に1本目が負けていた。決定20 の1本(単体)は、葉ペアの 50/50 混ぜや knn 0.1 混ぜより 40/40 ワールドで悪く、候補182本から補正CV 最良を1本目にすると真の誤差 −4.66±0.17(z −27)。その上で2本目を公開LB最良にすると非公開の損がさらに −0.31±0.09(公開20%、35/0)。ただし2本目の得の6割強は非公開の雑音の運で、真の誤差では −0.12±0.06(×10⁻⁴)

2026-10-15 金 / Phase 6(月替わりテーマ2: Playground Series 実戦投入) 分析→戦略 40ワールド・1,000 fit・候補182本・壁時計 6分45秒(M5 Pro・14並行)

📚 背景知識(読んでから問題へ)

Kaggle の最終提出の規則(今日のモデル)。 コンペの終わりに、自分の提出の中から最大2本を選ぶ。順位は、選んだ2本のうち非公開(private)LB で良い方で決まる。公開(public)LB は test の一部(Playground Series ではおおむね 20%)で、締め切りまで見える。非公開は残り(80%)で、締め切り後にしか見えない。

ここで大事なのは、2本目は損をしないということ。2本のうち良い方が数えられるので、2本目が1本目より悪くても順位は下がらない。問いは「2本目にどれを入れると一番得か」だけになる。

今日の前の決め方(CV設計書の該当部分)。

決定中身印(今日の前)
8HistGB に 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_Durint / floatDay163〜181 と同じ合成(ワールドの乱数 3000+番号)。低雑音16・小得12・中雑音12。train 3万・元1.5万・test 2万・truth 6万全候補
oof5(4, 13, 30000) float32lr0.05 の葉31〜255 × 本数13点(600〜1,200)の OOF(log)生CV・補正CV
oofk / tstk(30000) / (20000) float32k近傍(15近傍・標準化・5列)の OOF と test の5本平均knn 混ぜ
tst(4, 13, 20000) float32test の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) inttest のラベル(シミュレータなので持てる)公開/非公開の点数
保存先work/d182/r/{low,sm,mid}/raw182_w*.npz(計 350MB)・d182.pkltmp の外次回以降

評価指標(RMSLE)と、最終2本の数え方

RMSLE は log1p 空間の RMSE(小さいほど良い)。差はすべて ×10⁻⁴。最終順位は「選んだ2本のうち非公開で良い方」。だから2本目は損をしえず、問いは「どれを入れると一番得か」だけになる。下の図は、2本目を測る前に見つかった「1本目の負け」。

1本目の真の損(182本の真の最良との差、T5、×10⁻⁴、短いほど良い)灰=決定20(単体、Day181)、緑=決定22(182本から補正CV 最良)。対の差 −4.66±0.17、40/40低雑音4.690.49小得5.930.80中雑音5.590.79

❓ 問題

タスクA(予想を先に書く)

測る前に、次の4つに「当たる/外れる」と理由を書く。

  1. 1本目(決定20 の単体)は、候補182本の中でも真の最良に近い(損 1×10⁻⁴ 以下)
  2. 2本目に公開LB最良(182本から)を入れると、候補数が多いので公開LB に合わせすぎ、補正CV 2位を入れるより損をする
  3. 公開割合が小さい(5%)ほど、2本目に公開LB を使う得は消える
  4. knn 0.1 混ぜ(決定8)は、強くなった LightGBM の上ではもう得が無い

タスクB(コーディング)

  1. day181.py の生成部を1文字も変えずに、葉31〜255(600〜1,200本の13点)と k近傍の OOF・test 予測・truth 集計を作り、混ぜた候補は fold ごとに混ぜてから集計する day182.py を書く
  2. 600〜1,200本の OOF と truth 集計が Day181 の保存物と一致することを確かめる(再現)
  3. analyze182.py で、公開 5/20/50% × 再分割500回 の上で、2本目の方針ごとの非公開の損・真の誤差・2本目が勝つ割合を出す

タスクC(分析と決定)

  1. 2本目には何を入れるか。公開LB を使うか、補正CV の2位か、混ぜか
  2. 1本目は決定20 のままでよいか
  3. 「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(判定)

  1. 外れ(今日一番大きい外れ)。 決定20 の1本の真の損(182本の真の最良との差)は 低雑音 4.69・小得 5.93・中雑音 5.59(×10⁻⁴)。真の最良は 40/40 で混ぜた候補(葉ペア 31、knn 混ぜ 9)で、29/40 が s31+s255(一番小さい木と一番大きい木の 50/50)
  2. 後半(補正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本目は損をしない規則なので、害は「得が減る」形で出る)
  3. 当たり(向きは)。 1本目を補正CV 最良(182本)にしたあとの2本目の得は、公開 5% で −0.16±0.04、20% で −0.31±0.09、50% で −0.49±0.13。小さくなるが、5% でも 0 にはならない(2本目は損をしないので、得が小さくなるだけ)
  4. 外れ。 決定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. 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. 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本目は損をしえないので、慎重にする理由がない
  3. 2本目の得の6割強は運(決定12 に注記)。 公開20% で非公開の得 −0.31 のうち、真の誤差で残るのは −0.12±0.06。残りは「2本の非公開の雑音のうち良い方を取れる」得で、順位には効くが、モデルが良くなったわけではない。補正CV 2位の葉はもっと極端で、非公開 −1.08±0.18 に対し真 −0.30±0.19(2SE 未満)。2本目の評価を非公開の点数だけで書くと、雑音の運をモデルの力と読み違える
  4. 決定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本)になったら公開最良の合わせすぎを測り直す
13CV の直し方補正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.27knn を外す: 中雑音では真の最良の 8/12 が knn 混ぜ—
20(役割変更)単体の作り直しは部品にする決定22 の候補の一部として残る廃止: 単体の本数選び(600〜1,200)は混ぜの部品の質に効く—

📊 結果の可視化

40ワールド(低雑音16・小得12・中雑音12)、1,000 fit(LightGBM 800 は各1,200本+knn 200)、候補182本 × 再分割500回 × 公開割合3通り。600〜1,200本は Day181 の保存物と OOF が完全一致。
2本目の方針: 「決定20 の1本だけ」との非公開の損の対の差(公開20%、×10⁻⁴、左ほど良い)ひげ=±2SE(40ワールド)。上位はどれも「混ぜた候補」を拾った方針。1本目を替えるだけで −4.94-6-5-4-3-2-1+0+1[1本目も替える] 補正CV最良+公開LB最良-5.25±0.26葉ペア混ぜの補正CV最良-5.14±0.28[1本目も替える] 補正CV 1位+2位-5.04±0.27補正CV 2位(182本全体)-4.95±0.27[1本目も替える] 補正CV最良のみ-4.94±0.27公開LB最良(狭い6本)-4.39±0.29公開LB最良(広い182本)-4.17±0.25knn 0.1 混ぜ(決定8)-3.10±0.31ガード(−2SE なら公開最良)-2.88±0.29補正CV 2位の葉(単体)-1.08±0.18
1本目=決定22 の上で2本目(公開LB最良)を足す得: 非公開の点数 対 真の誤差(×10⁻⁴)橙=非公開の損の対の差(順位に効く得)、青=勝った方の真の誤差(T5)の差(モデルの力)。差の部分が雑音の運-0.6-0.4-0.2+0.0公開 5%非公開 -0.16±0.04真 -0.04±0.03(25%)公開 20%非公開 -0.31±0.09真 -0.12±0.06(39%)公開 50%非公開 -0.49±0.13真 -0.19±0.08(39%)

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 から

📝 自己評価(解いた後に記入)

自分の回答・気づき・メモ: