BoatraceCSV

Phase 0: 確率的スリット (slit_sim) 校正結果

docs/design/slit_sim_plan.md §2 の受け入れ判定。

結論

隊形確率・決まり手確率は不合格。撤退ライン 1・2 も不成立。撤退ライン 3(ST 帯のみ)で実装する。

対象 判定
隊形 6 分類 + 決まり手(本命案) FAIL(4 基準すべて)
撤退 1: 隊形 3 分類 FAIL(校正)
撤退 2: 決まり手を落とす FAIL(撤退 1 が前提のため同時に不成立)
撤退 3: ST 帯 (p25〜p75) のみ PASS

再現:

python notebooks/st_estimation/build_panel.py . notebooks/slit_sim
python notebooks/slit_sim/calibrate.py         # 本命案の判定
python notebooks/slit_sim/diagnose.py          # 不合格の原因切り分け
python notebooks/slit_sim/retreat.py           # 撤退 1 / 2 の判定
python notebooks/slit_sim/band_calibration.py  # 撤退 3 の判定

1. 本命案(隊形 6 分類 + 決まり手)— FAIL

推定した定数: BETA = 0.758 / SIGMA_BY_COURSE = {1C 0.048, 2C 0.045, 3C 0.040, 4C 0.042, 5C 0.044, 6C 0.053} / 進入コース別オフセット {1C -0.009, 2C -0.002, 3C -0.008, 4C -0.005, 5C -0.002, 6C +0.012} / K_SIGMA = 5 / Student-t(df 6.03)。

基準 結果 判定
1. in_margin 分布 mean 実測 -0.513 / MC -0.629、\|·\|≦0.6m 実測 55.6% / MC 44.7% FAIL
2. 隊形の周辺確率 「半艇身遅れ/センター」で +6.5pt 乖離(基準 ±3pt) FAIL
3. 決まり手の五分位校正 逃げ 11.0pt 乖離(基準 ±5pt) FAIL
4. 隊形 Brier MC 0.6402 vs 定数予測 0.6343 — 定数に負ける FAIL

基準 4 が本質的。レースごとに確率を出す意味が無い(全レース一律に周辺分布を答えるほうが良い)。

進入コース別オフセットは racer_st.COURSE_OFFSET と同値になった。両者とも 同じ学習窓・同じ残差から引いているため。バグではない。


2. 不合格の原因(diagnose.py)

2.1 決定的: スリット隊形は事前情報でほぼ説明できない

in_margin(1 コースが外の最先行艇より前に出ている量)について:

corr(実測 in_margin, 予測 in_margin) = 0.197   →   R² = 0.039

分散の 3.9% しか事前に説明できない。 どんなサンプリング設計にしても、出力は ほぼレース非依存の定数に潰れる。基準 4 で定数予測に負けたのはこの直接の帰結。

2.2 レース単位の散らばりも予測できない

レース内 ST 散らばり(sd of dev)は平均 0.0428・CV 0.537 と大きく振れるが、 事前に分かる変数と相関しない:

説明変数 corr
A1 級の人数 -0.109
風速 0.065
波高 0.060
場(場間 sd 0.0022 / レース間 sd 0.0230 = 分散の 1% 未満) -0.016
同一場の直近 50 走平均 0.089

「今日は締まったスリットになりそう」を事前に言い当てる手がかりが無い。

2.3 独立ノイズでは芯の鋭さと裾の重さを同時に再現できない

モデル sd \|in_margin\|≦0.6m 尖度
実測 0.881 56.7% 95.8
正規 σ=0.036 0.601 49.1% 0.00
正規 σ=0.048 0.805 37.2% 0.06
混合(実測の散らばりをリサンプル = オラクル) 0.898 49.3% 76.4

最終行は「そのレースが実際どれだけ散らばったか」を先に知っているズルい設定だが、 それでも ≦0.6m は 49.3% にしかならず実測 56.7% に届かない。 独立ノイズという構造自体が実測の隊形分布と合っていない。


3. 撤退ライン 1 / 2 — FAIL(retreat.py)

隊形を 3 分類(イン先手 / 揃い / イン遅れ)に粗くして、σ スケールを 0.60〜1.40 で 全探索した。3 指標(周辺 ±3pt・Brier が定数未満・五分位校正 ±5pt)を同時に満たす スケールは存在しない。

scale 周辺差(pt) Brier 定数比 校正乖離(pt)
0.70 2.52 -0.0122 9.53
0.75 1.24 -0.0143 7.49 ← 校正が最良でも基準超過
0.80 3.61 -0.0133 8.81
1.00 12.63 +0.0113 13.75

テスト窓(scale 0.75)では周辺 ±1.4pt・Brier は定数比 +1.73% と改善するが、 五分位校正が 8.0pt 乖離して落ちる:

「揃い」予測確率 n 予測 実際
最下位五分位 1,562 0.374 0.438
中位 1,553 0.585 0.569
最上位五分位 1,551 0.724 0.644

高確率側で一貫して過信。σ を広げると校正は改善せず周辺分布が壊れる(上表)。 事後に確率を縮める再校正で数字は繕えるが、それは §2.1 の 「R² = 0.039」を隠すだけで、レースごとの情報は増えない。採らない。


4. 撤退ライン 3(ST 帯)— PASS(band_calibration.py)

隊形の確率は諦め、各艇の ST の予測区間だけを出す案。テスト窓 47,000 艇走で判定。

4.1 被覆率(基準 A)

予測残差 sd = 0.0684 秒、標準化残差の超過尖度 2.4 → Student-t(df 9.14, scale 0.879)。

名目 正規の実被覆 差 Student-t の実被覆 差
50% 53.5% +3.5pt 49.6% -0.4pt
80% 83.0% +3.0pt 80.7% +0.7pt
95% 95.6% +0.6pt 95.8% +0.8pt

Student-t で全水準 ±1pt 以内。 分布形は t を採用する。

4.2 選手別 σ に意味があるか(基準 B)

racer_sd_raw を K_SIGMA=10 で収縮した相対倍率で帯幅を変える。

σ 分位 n 帯幅(秒) 被覆(選手別σ) 被覆(帯幅一定)
最安定 9,400 0.0695 0.487 0.572
2 9,400 0.0768 0.488 0.530
3 9,400 0.0819 0.493 0.506
4 9,400 0.0875 0.497 0.482
最不安定 9,400 0.1002 0.518 0.448

分位間の被覆ばらつきが 0.124 → 0.031 に縮む(名目 0.50)。 帯幅一定だと安定型は 57%・不安定型は 45% しか覆えず、区間の意味が選手で変わってしまう。 選手別 σ を入れる価値がある。(pinball loss は +0.21% と僅差だが、 この指標は帯幅の当否に鈍いため被覆の一様性で判断した)

4.3 帯の幅(UI 判断材料)

p25〜p75 の幅は中央値 0.082 秒 = 1.14m(10-90 分位 0.070〜0.097 秒 = 0.98〜1.35m)。 艇長 3m = ST 差 0.216 秒なので、四分位帯でおよそ 0.4 艇身。 点で描くのとは明らかに見た目が変わり、「スリットは決め打ちできない」ことが図から伝わる。

4.4 凍結する定数

band_report.json に出力済み。

SIGMA_BASE = 0.0684        # 予測残差 sd (帯の基準幅)
K_SIGMA    = 10.0          # 選手別 σ の収縮
SD_PRIOR   = 0.0664        # racer_sd_raw の全体平均 (相対倍率の分母)
DIST       = "t", T_DF = 9.14, T_SCALE = 0.879
COURSE_OFFSET_ENTRY = {1: -0.0090, 2: -0.0015, 3: -0.0075, 4: -0.0045, 5: -0.0016, 6: 0.0119}

5. 次段への申し送り