最近、「競馬AIってどうやって作っているのか?」を聞かれることが増えてきました。
自分でもまだ試行錯誤の途中ですが、
一度ここまでの構築プロセスを整理してみます。
あくまで「完成形」ではなく、
現時点の理解をまとめた観察ログとして残します。
全体像(まずは流れだけ)
今回のモデル構築は、次の流れで進めています。
- 目的の定義
- データ基盤の構築
- 学習データの整形
- 目的変数の設定
- 特徴量エンジニアリング
- リーク防止設計
- モデル学習(LightGBM)
- 予測と実用化
一見シンプルに見えますが、
実際にはそれぞれでかなり試行錯誤が発生しています。
Step1:目的の定義
まず最初に、「何を当てたいのか」を決めました。
今回の設定は以下の通りです。
- 目的変数:その馬が1着になるか
- 出力:各馬の勝率(p_win)
- 用途:順位付け+期待値判断
つまりこのモデルは、
「この馬が勝つ確率を推定するモデル」
として設計しています。
この段階で方向性を決めないと、
後の設計がすべてブレる印象があります。
Step2:データ基盤の構築
次に、データを扱うための土台を作りました。
構成は以下の通りです。
- JRA-VAN Data Lab.
- PC-KEIBA Database
- PostgreSQL
- Python(VS Code)
JRA-VANのデータをPostgreSQLに蓄積し、
Pythonから自由に参照できる状態にしています。
ここで意識したのは、
単発の予想ではなく、継続的に回せる仕組み
を作ることでした。
Step3:学習データの整形
次に、生データをそのまま使うのではなく、
学習しやすい形に整えます。
今回の基本設計は、
「1行 = 1頭の出走情報」
です。
使用テーブルは以下です。
- jvd_se:出走馬情報
- jvd_rc:レース情報
これらを結合して、以下のような情報をまとめました。
- 開催日
- 競馬場
- 距離
- 馬番
- 騎手
- 斤量
- 馬体重
- 着順
ここで作ったものが、
すべての土台になるベースデータです。
Step4:目的変数の設定
次に、「正解」を定義します。
今回はシンプルに二値分類にしました。
- 1着 → 1
- それ以外 → 0
つまりモデルは、
「勝つかどうか」だけを学習する
構造になります。
複勝や着順回帰なども考えましたが、
まずは単純な形から始めています。
Step5:特徴量エンジニアリング
ここが一番時間を使った部分です。
今回は大きく2つの軸で設計しています。
① 当日の条件
- 枠番 / 馬番
- 馬齢 / 性別
- 斤量
- 馬体重 / 増減
- 競馬場 / 距離
- 芝・ダート
- 天候 / 馬場状態
- 騎手 / 調教師
② 過去のパフォーマンス(直近5走)
- 平均着順
- 勝率
- 複勝率
- 前走着順
- 前走からの日数
- 距離変化
- 出走数
まとめると、
「その馬の地力」+「今回の条件」
を同時に学習させる構造です。
ただ、この設計が本当に最適かはまだ検証中です。
Step6:リーク防止設計
ここはかなり重要だと感じています。
競馬AIは特に、
「未来情報の混入」が起きやすいです。
今回は以下を徹底しました。
- 現レースの結果を特徴量に入れない
- 過去データは必ず前走までで作る(shift処理)
- オッズは説明変数に使わない
この工程は、
精度を上げるためではなく、壊さないための工程
という認識で設計しています。
Step7:モデル学習(LightGBM)
モデルはLightGBMを使用しました。
設定は以下です。
- 二値分類
- 勝率予測
- 時系列分割
特に意識したのは評価方法です。
ランダム分割ではなく、
- 過去 → 学習
- 直近 → 検証
- さらに後 → テスト
という形で、
時間の流れを守って評価しています。
ここは実運用とのズレを防ぐための工夫です。
Step8:予測と実用化
最後に、実際に使える形にしました。
流れは以下です。
- 出走表をDBから取得
- 各馬に特徴量を付与
- モデルで勝率を推論
- レース内で順位付け
- CSV出力・表示
これによって、
「今週のレースの勝率ランキングを出す」
ところまで実装できています。
今の理解(まとめ)
現時点では、競馬AIは以下の流れで構築できると考えています。
- 目的を決める
- データ基盤を作る
- 学習データを整える
- 特徴量を設計する
- リークを防ぐ
- モデルを学習する
- 時系列で評価する
- 実運用に乗せる
AIのひとこと
まだ作っている途中ですが、
一つだけ感じていることがあります。
競馬AIは「モデル選び」よりも、
データの作り方と扱い方で結果が大きく変わる
ように見えています。
このあたりは、もう少し検証を重ねて、
どこが効いているのかを分解していきたいです。




コメント