1. はじめに
この記事では、自作競馬AIで分類学習からランキング学習へ切り替えたら精度と回収率が大きく改善した話を、備忘録的にまとめます。
開発の裏で起きた
- なぜ分類がうまく機能しなかったのか?
- なぜランキング学習が当てはまったのか?
- どうスコアを馬券戦略に落としたのか?
なども整理しつつ、
今後競馬AIを作る方の参考になれば嬉しいです。
以下簡単ですが、自己紹介です。
- 競馬は2022年からやっています
- 馬券は単複とか馬連ワイド1点ずつみたいに絞って買うスタイル
- 無駄な馬券は買わないがモットーです
- 2024年9月ごろから競馬予想AIの開発をはじめました(ChatGPTに基本丸投げ)
2. 変遷と課題(2024~2025)
これまでの競馬AI開発の歴史(?)と課題点をにご紹介します。
競馬AIに関して
- 環境:GoogleColab(すぐ始められるから)
- データ:JRA-VAN TARGET
- 言語:Python
2024年秋:初号機爆誕
- 学習:分類
- タスク:3着以内に来る馬を予測する
- 「とりあえず作ってみよう!」のモチベーションで作成
- 的中率は60%ぐらい、回収率は70%ぐらいだった
2024年11月末:2024_v4爆誕
- 学習:分類
- タスク:5着以内に入る馬を予測する
- 初号機からいろいろこねくりまわしてできたモデル
- 学習が安定するように3着以内から5着以内にTrueラベルを増やした
- 穴っぽい馬を学べるような特徴量を投入
- 2024年11月~12月はそれなりに当たりおいしい思いができたが、2025年1月~2月に文字通り1つも当たらなくなった
- 単複でみると的中率は60%程度、回収率は80%程度
- 条件付きで回収率が100%を超えた
2025年4月~2025年9月:分類モデルでの試行錯誤
- 学習:分類
- タスク:いろいろ
- 3着内に入る馬を予測する
- 5番人気以上で5着以内に入る馬を予測する
- 単勝オッズ10倍以上で〇着以内に入る馬を予測する...etc
- 距離別にモデル(学習)を分けることで、PR-AUCが過去のモデルより良くなった
- しかし、馬券構築への落とし込みが難しくなる
- 的中率は60%をなかなか超えられず、回収率も100%を超えられず…
これまでに感じたこと
- 目的に対してタスクがブレブレであった
- スコアをうまく馬券に落とし込めない
- 馬券戦略がかみ合わない
- レース内での馬の序列づけや比較ができてないと感じた
- 的中率、回収率の壁
3. Ranking学習への移行
これまで感じていたことからモデルの設計を見直すことにしました。
モデルのスコアをどう馬券に落とし込むのかまでをイメージしモデルの役割を明確にすることからはじめ、最終的には2つのモデルを構築することにしました。
ひとつはレース内での能力が最も高い馬(=3着以内に入る可能性が高い馬)を予測するモデルで、「Abilityモデル」と呼びます。とにかく的中率を求めるようタスクを設定しました。
もうひとつは期待値のある馬(=市場評価を覆し3着以内に入る可能性が高い馬)を予測するモデルで、「ANAモデル」と呼びます。こちらは回収率を求めるようタスクを設計しました。
また、これらのモデルに関して、比較ということがポイントになってくるので、学習方法をランキング学習へ変更しました。特徴量は変えませんでした。
※ランキング学習とは
同一グループ内(今回は各レース)でサンプル間の相対順位誤差を最小化する学習手法です。
LightGBMではrankerとして実装されています。
以下は検証データでの結果です。
(実際の表とかだせたらよかったのですがメモ程度しか残っておらず…)
Abilityモデル
- スコアが高い馬ほど的中率の信頼性が高まる
- 一定のスコア以上での的中率は 70%超え
ANAモデル
- 一定のスコア以上であれば回収率は100%over
- こちらもスコアに比例して的中率、回収率が良化
馬券戦略も改善
-
スコア閾値を設定
-
Ability × ANA の組み合わせで
馬連・ワイド・馬単をシステム的に“1点だけ”買う方式
→ これがプラス収支を達成中(2025/9~2025/12)
→投資:¥21000 回収:¥29350 回収率:139.8%👏 -
ほかにも、Abilityモデルの高スコア馬で複コロ!とか、自身の本命馬の相手としてAbilityモデルの馬を利用!とかでうまく馬券にも活用できている
4. なんでここまでかわるかChatGPTに聞いてみた
最後に、「分類 → ランキング学習」への変更だけで成績が改善した理由をChatGPTに聞きました。
返ってきた内容を要約すると、以下の技術的ポイントが効いていたようです。
理由①:損失関数が目的と一致した
分類学習(分類タスクはクロスエントロピー損失を用い)は「正例を当てる能力」を最大化しますが、ランキング学習(Pairwise / Listwise 系損失)は“順位の正しさ” を直接最適化します。
競馬は順位ゲームのため、損失関数の目的が問題設定と一致したことが大きいとのこと。
理由②:同一レース内の比較学習が可能になった
分類では「異なるレース間のサンプルを横並びに分類」するため、レース文脈が薄れます。
一方ランキング学習は、同レース内のサンプル同士を比較しながら重み更新が行われるため、展開・馬場・距離・斤量といった“レース固有の条件下での強さ順を学習できます。
結果として、能力順位がそのまま馬券に結びついたとのこと。
理由③:スコアが相対尺度になる
分類モデルの出力は
p = 3着以内確率っぽい何か(曖昧)
で、閾値設計が非常に難しい。
しかしランキング学習では、
score差 = 相対順位上の距離として扱いやすい
の形になり、スコアの解釈が“能力序列”として自然に扱える
→ 阪神芝1600でも、東京ダ1600でも同じロジックで買える
理由④:モデルのランキング指標が評価軸と一致
競馬では「上位2頭を当てる」などが目的なので、ランキング学習で最適化されるNDCG、MAP、Hit@Kといった評価指標が実際の馬券目標と構造的に一致していたらしい。
理由⑤:オッズ情報とのズレが特徴量として活きる
ANAモデルの場合、人気上位より能力上位が高い馬を拾うと回収率が伸びる。
ランキング学習は人気上位と能力上位の “順位の差分” を学習しやすい構造なので、期待値部分が顕著に改善したとのこと。
まとめ
競馬自体が “順位付けタスク” なので、そのまま順位を学習する手法に変えたことで
損失関数・評価指標・スコア解釈・データ構造が全て競馬と噛み合った。
その結果、特徴量を変えずに性能が劇的改善したのは手法変更が目的と噛み合ったことが改善につながったという話でした。
理由①や②には特に納得できる内容でした。
もっと早くから知れていればなあという気持ちでいっぱいです。
5. 学んだこと
- 最初の動き出しはやってみようのノリでよかったけど、ブラッシュアップするのなら闇雲に進めるのはダメ、絶対
- 何をしたいのかが明確でないと貴重な時間とお金を溶かすことが分かった
- 目的に従って適切な学習手法を選択し、タスクを設定し、特徴量を作成する(あたりまえだが)
- ここに関してはコアとなる知識がベースとしてが必要
- ドキュメントを整備して残しておくべき
- 面倒だがテンプレとかにしておく仕組みでうまいことやろう
6. 今後の展望
- AWS上で動くものにしたい
- レースのペースを予測するモデルをつくって組み合わせたり、特徴量やタスク設定を変えたりしてより確実に勝てるモデルへアップグレードしたい
拙い記事でしたが、最後まで読んでくださりありがとうございました。
(今週末は有馬記念ですね!楽しみましょう!)