プロローグ:見たくなかった数字
2026年5月2日(土)。
新しいシステムでの初実戦。
期待を込めて予測を実行した。
リベルタアーラ(11番人気、35.0倍): 予測勝率: 27.9% 期待値: 876.9%
…は?
876.9%?
11番人気の馬が、27.9%の確率で勝つ?
明らかにおかしい。
この瞬間から、数時間に及ぶ格闘が始まった。
📊 第10週の結果
5/2(土)
投票なし 理由: システム不具合のため
異常な予測値を見て、即座に運用を停止した。
5/3(日)
システムを完全に作り直し、新システムで再挑戦。
| 項目 | 数値 |
|---|---|
| ベット数 | 12頭 |
| 投資額 | 1,200円 |
| 払戻額 | 0円 |
| 収支 | -1,200円 |
| 回収率 | 0.0% ❌ |
| 的中数 | 0頭 |
| 的中率 | 0.0% |
12頭すべて外れ。
厳しい結果だが、これは後で分析する。
🔍 システム不具合の発見
異常な予測値
5/2朝、race20260502.csvで予測を実行した。
出力された推奨馬リスト:
リベルタアーラ(11番人気、35.0倍): 予測勝率: 27.9% 期待値: 876.9% ← ありえない アムールドパリ(15番人気、57.7倍): 予測勝率: 3.4% 期待値: 96.9% ← 異常 ロックウイズユー(5番人気、10.7倍): 予測勝率: 16.0% 期待値: 70.7% ← おかしい
11番人気が27.9%で勝つ?
期待値876.9%?
完全に壊れている。
第8週・第9週も同じ症状
遡って確認すると、第8週・第9週の惨敗も同じ原因だった。
第8週: 回収率41.7% 第9週: 回収率5.1% → システムのバグが原因
つまり、第8週から壊れていた。
💡 原因究明の記録
仮説1: モデルファイルが壊れている?
まず、モデルを単体でテスト:
11番人気、35.0倍の馬を予測: 予測勝率: 1.86% 期待値: -34.92% ✅ モデルは正常
モデルは正しく動作している。
仮説2: 予測スクリプトに問題?
スクリプトのコードを確認:
predicted_probs = model.predict_proba(X)[:, 1] ✅ コードも正常
スクリプトも問題なし。
仮説3: データの前処理?
CSVから読み込んだリベルタアーラのデータを確認:
馬名: リベルタアーラ 人気: 11 オッズ: 35.0 芝ダ: 芝 距離: 2000 性別: 牝 年齢: 3
データも正常。
決定的な発見
実際の特徴量で予測してみた:
11番人気、35.0倍、2000m、牝、3歳: 予測勝率: 27.91% 期待値: 876.92% ❌ 異常!
でも、デフォルト値(1600m、牡、4歳)で予測すると:
11番人気、35.0倍、1600m、牡、4歳: 予測勝率: 1.86% 期待値: -34.92% ✅ 正常
特定の特徴量の組み合わせで異常な予測をする。
根本原因
さらに調査を進めた結果、判明した。
問題の特徴量:odds_popularity_gap
これは、オッズと人気の差を表す派生特徴量:
odds_popularity_gap = オッズ - (人気 × 2)
この特徴量が、モデルを混乱させていた。
特に:
- 距離が長い(2000m)
- 牝馬
- 若い(3歳)
これらの組み合わせで、異常な予測をする。
つまり、モデルが過学習していた。
🔧 完全再構築
方針
派生特徴量をすべて削除し、基本特徴量のみで再学習する。
削除した特徴量
- odds_popularity_gap ← 諸悪の根源
- distance_category
- odds_category
使用する特徴量(8個)
- popularity(人気)
- odds(オッズ)
- track_condition_encoded(馬場状態)
- track_type_encoded(芝ダ)
- distance(距離)
- horse_weight(馬体重)
- sex_encoded(性別)
- age(年齢)
モデルパラメータ
過学習を防ぐため、パラメータも調整:
n_estimators: 100 max_depth: 4(浅め) min_samples_leaf: 50(過学習防止) subsample: 0.8
学習結果
テストケース1: 11番人気、35.0倍、2000m、牝、3歳 予測勝率: 1.75% 期待値: -38.59% ✅ 正常! テストケース2: 1番人気、1.5倍、1600m、牡、4歳 予測勝率: 56.59% 期待値: -15.12% ✅ 正常!
完璧に動作する。
📈 新システムの性能
バックテスト結果
2024年10月〜12月のテストデータで検証:
| 項目 | 値 |
|---|---|
| 期間 | 2024年10月〜12月 |
| ベット数 | 858頭 |
| 的中数 | 23頭 |
| 的中率 | 2.7% |
| 投資額 | 85,800円 |
| 払戻額 | 71,940円 |
| 収支 | -13,860円 |
| 回収率 | 83.9% |
期待値の閾値
閾値を変えて、最良の設定を探した:
期待値 5%以上: 回収率70.6% 期待値10%以上: 回収率74.7% 期待値15%以上: 回収率83.9% ← 最良 期待値20%以上: 回収率45.4%
期待値15%以上が最良と判明。
新システムの特徴
- ✅ 異常な予測値なし
- ✅ すべて妥当な範囲(期待値15-50%)
- ✅ バックテスト検証済み(回収率83.9%)
- ✅ 過学習なし
📊 5/3の結果と分析
推奨馬の着順
新システムで推奨された12頭の結果:
リュウゴピュア(新潟3R): 7着 予測勝率: 2.4%、期待値: 50.7% カウガールハット(東京3R): 12着 予測勝率: 2.3%、期待値: 48.4% ロックウイズユー(新潟6R): 6着 予測勝率: 13.1%、期待値: 40.1% ログラール(東京9R): 16着 予測勝率: 17.9%、期待値: 30.7% (他8頭も外れ)
12頭すべて外れ。
回収率0.0%。
統計的な評価
期待される的中数を計算:
12頭の予測勝率の合計: 2.4% + 2.3% + 13.1% + ... = 約120% 期待的中数: 約1.2頭 実際の的中数: 0頭 → 統計的には誤差範囲内
判断
サンプル数が少なすぎて判断できない。
バックテストでは858頭で83.9%を達成している。
12頭(1週間)で判断するのは早計。
最低3週間(30-40頭)は続ける。
💭 エピローグ:データサイエンスの本質
学んだこと
1. 異常値は見逃さない
期待値876.9%という数字を見た瞬間、即座に運用停止した。
データサイエンスでは、異常値は必ず原因がある。
2. 問題の切り分けが重要
✅ モデル単体は正常 ✅ スクリプトも正常 ✅ データも正常 ❌ 特定の組み合わせで異常 → 特徴量エンジニアリングの問題
1つずつ検証して、原因を特定した。
3. シンプルが最強
派生特徴量を削除し、基本特徴量のみにした。
結果、正しく動作するようになった。
複雑さは敵。
4. 短期で判断しない
1週間で回収率0%。
でも、バックテストでは858頭で83.9%。
長期で評価する。
次週への期待
新システムの初戦は厳しい結果だった。
でも、システムは正しく動作している。
予測値は妥当。
バックテストも通過。
あとは、データを蓄積して評価するだけ。
📊 累計データ
第1-9週(旧システム)
| 項目 | 値 |
|---|---|
| ベット数 | 587頭 |
| 投資額 | 58,500円 |
| 払戻額 | 50,240円 |
| 収支 | -8,260円 |
| 回収率 | 85.9% |
※ 第8週・第9週はシステム不具合のため、参考値
第10週(新システム)
| 項目 | 値 |
|---|---|
| ベット数 | 12頭 |
| 投資額 | 1,200円 |
| 払戻額 | 0円 |
| 収支 | -1,200円 |
| 回収率 | 0.0% |
🔜 次回予告
次回は、第11週の結果を報告します。
新システムで、どこまで回復できるか。
3週間のデータで、システムの真価が見える。
📝 まとめ
第10週は、システムの完全再構築の週でした
異常な予測値を発見。
数時間の調査で根本原因を特定。
派生特徴量が原因と判明。
システムを完全に作り直し。
新システムは正常に動作。
でも、初戦は回収率0%。
統計的には誤差範囲内だが、厳しい結果。
データサイエンスは、短期で判断しない。
長期で評価する。
次週以降、データを蓄積して検証していく。
最後まで読んでいただき、ありがとうございました!
「システム再構築、お疲れ様」
「0%は厳しいけど、続けてほしい」
「データサイエンスの姿勢に共感」
コメントお待ちしています 💬