競艇AIの検証で良い数字が出たら、まず候補選びや期待値計算に確定オッズを使っていないかを確認してください。確定オッズは締切後に決まる値で、舟券を買う時点では知ることができません。筆者の最初の検証もこの状態で、締切前のライブオッズだけに直すと単勝ベースラインはROI -7.64%になりました。
この記事では、シリーズ第2回として、確定オッズによるデータリークの見つけ方と、締切前オッズを時刻付きで集め、品質を確認する方法をまとめます。
この記事の結論
- データリークは特徴量だけでなく、「買う条件(戦略)」と「リターン計算」にも入り込む。
- 確定オッズを外し、時点付きライブオッズだけで候補を作ると、単勝ベースラインは9,114ベットでROI -7.64%になった。
- オッズは値だけでなく、取得時刻・締切時刻・締切までの残り時間・レースID・艇番と一緒に保存する。
- 「4分前(T4)」として保存されたデータにも、締切後取得が6件、余裕1分未満が76件混ざっていた(5,906レース中)。除外してから使う。
- 払戻を読む処理から候補選びに戻れないデータの流れにする。
症状:最初の検証結果が良すぎた
着順や払戻はモデルに入れておらず、特徴量のリークには気をつけていました。それでも最初の検証は良い数字でした。
原因:戦略の条件とリターン計算に確定オッズを使っていた
見落としていたのは戦略側です。「このオッズなら期待値がプラスだから買う」という判断に確定オッズを使い、的中時のリターン計算にも確定オッズを使っていました。モデルは正しくても、買い方の部分で締切後の情報を見ていたことになります。
各工程で使ってよい情報の時点を整理すると、次のようになります。
| 工程 | 使ってよい情報 |
|---|---|
| 確率の計算(特徴量) | 出走表、選手、モーター、展示 |
| オッズの取得・期待値の計算・候補の選定 | 時点が確認できる締切前ライブオッズ |
| 教師ラベル・払戻の精算 | 着順、払戻、確定オッズ |
確定オッズは精算では正しい値でも、候補選びでは使ってはいけない値です。
修正後の結果:ROI -7.64%
確定オッズを候補選びから外し、時点付きライブオッズだけで候補を作る形に直すと、既存の単勝ベースラインは9,114ベットでROI -7.64%になりました。最初の良い数字は実運用の根拠にせず、この修正後の数字を基準にしています。
ネット上で手に入るのは確定オッズだけで、締切直前のオッズは残っていないため、オッズを自分で集めながら開発しています。現在のデータ量なら妥当な水準だと受け止めています。
対処1:オッズを時刻付きの観測として保存する
snapshot = {
"race_id": race_id,
"boat_no": boat_no,
"odds": odds,
"odds_timestamp": observed_at.isoformat(),
"close_time": close_time.isoformat(),
"minutes_to_close": (close_time - observed_at).total_seconds() / 60,
}
対処2:「4分前」のラベルではなく実際の取得時刻で確認する
ライブ評価では締切約4分前(T4)のオッズを使っていますが、スケジューラやサイト応答の遅れで、ラベルと実際の取得時刻がずれることがあります。
| 確認項目(結合できた5,906レース) | 件数・値 |
|---|---|
| 取得時刻が欠けていた | 0件 |
| 締切後に取得していた | 6件 |
| 判断に使える余裕が1分未満 | 76件 |
| 実際の取得時刻の中央値 | 締切3.78分前 |
| 判断した時刻の中央値 | 締切3.74分前 |
締切後取得と余裕不足の行は候補にする前に除外します。「4分前」という名前・実際の取得時刻・判断の余裕を別々に記録すれば、こうしたずれをモデル性能の問題と取り違えずに済みます。
対処3:ROIの前にデータの件数を段階ごとに数える
| 段階 | 件数 | 意味 |
|---|---|---|
| 集めたスナップショット | 6,258 | 締切前に観測した単位 |
| 集めた艇の行 | 37,485 | 取得できたオッズの行 |
| 予測・払戻・ライブオッズを結合できた | 5,906レース / 35,375行 | 評価に使える母集団 |
| 市場の確率を計算できた | 4,505レース | 有効なオッズが5艇以上そろった |
集めたデータの一部しか評価に使えていないことが分かります。欠けた分を埋めるより、何件がどんな理由で外れたかを示すほうが、ROIを正しく読む助けになります。
毎日集計しているデータ品質レポート
- 取得予定のレース数と、取得に成功したレース数
- 6艇のオッズがそろった割合
- 締切までの時間の分布
- 結果と結合できた割合
- 見送り理由ごとの件数
どれかが急変した日は、ROIの計算に入れる前に原因を確認します。除外するときも、成績を良く見せる除外にならないよう、ルールと件数をレポートに残します。
対処4:払戻が候補選びに戻らないデータの流れ
- 締切時刻を含む開催スケジュールを取得する
- T4で単勝オッズを保存し、取得時刻と艇番を一覧に追記する
- 予測と時点付きオッズを、レースIDと艇番で結合する
- 候補と見送りを台帳に記録し、固定する
- 結果確定後に公式の払戻データを結び、損益を集計する
この順番なら、払戻を読む処理から候補選びに戻る経路がそもそもありません。リーク対策は1行のチェックを足すことではなく、データの流れそのものを分けることです。
オッズが取れなかったレースの扱い
サイトの応答やスケジューラの障害でT4のオッズが取れなかったレースは、確定オッズで穴埋めせず「市場情報なし」として候補から外します。評価対象は減りますが、買えなかった条件を買えたように見せるよりはるかに安全です。
まとめ:競艇AIのデータリーク確認チェックリスト
- 候補選び・期待値計算に確定オッズを使っていないか
- オッズに実際の取得時刻と締切時刻が保存されているか
- 締切後取得・判断余裕不足の行を除外しているか
- 段階ごとの件数と除外理由をレポートしているか
- 払戻データが候補選びに戻らない流れになっているか
次回は、LightGBMで出した勝率を市場の確率と比べ、候補を台帳に出すまでの仕組みを解説します。
注意:本記事は個人開発・データ分析の記録です。的中や利益を保証するものではなく、舟券の購入を勧めるものでもありません。