結論から言います
競馬AIと競艇AIは「別のスポーツのAI」というだけでなく、開発の難しさの質がまるで違います。
私は競艇AIをまず作り、LightGBMで単勝的中率55%・回収率96%程度まで持っていってから、「競馬でも同じことができるはず」と思って競馬AIに手を出しました。結果として、競馬AIの単勝的中率は32%・回収率81%という水準にしか到達できていません(2026年5月現在)。
競艇AIとの最大の違いは次の3点です。
- データ取得の難しさ(構造と入手経路)
- 特徴量の複雑さ(変数の種類と相互作用の多さ)
- オッズの更新タイミング(最終直前の動きが激しい)
この3つについて、競艇AIを作った視点から正直に書きます。
なぜ競馬AIに挑戦したのか
競艇AIを半年ほど動かして、ある程度の手応えを得ていました。ざっくりした数字をお伝えすると、競艇AIは単勝的中率55%・回収率96%で落ち着いています。100円賭けて平均96円が返ってくる水準です。勝ちとは言えませんが、「機械学習で公営ギャンブルの予測が一定レベルでできる」という感触は掴めました。
次に何かやろうと思ったとき、頭に浮かんだのが競馬でした。競艇より市場規模が大きく、データも豊富で、ネット上の先人の知見も多い。競艇AIで学んだノウハウをそのまま使えると思っていました。
甘かった。
競馬AIの開発を始めて1ヶ月後、私は競艇AIのコードがほぼ流用できないことに気づきました。
違いポイント①:データ取得(競馬のデータ構造は格段に複雑)
競艇のデータ取得はシンプルです。公式サイト(boatrace.jp)から取れる情報が整理されており、出走表・結果・選手成績がある程度フォーマットとして決まっています。
競馬の場合、主なデータソースとしてよく使われるのは netkeiba.com や JRA公式 です。ただし、競馬のデータ構造には競艇にない複雑さがあります。
競馬データ特有の問題
馬ごとに異なるレース履歴
競艇では選手ごとの成績を取得すればよく、データのキー構造が比較的シンプルです。競馬では「馬のID」「騎手のID」「調教師のID」「馬主のID」が別々に管理されており、1レースを記述するためのエンティティが競艇より多い。過去レース履歴を結合するときに複数のIDをまたぐ処理が必要になります。
レース条件の多様性
競艇は6人が同じルールで戦います。競馬は距離(1200m〜3600m以上)・馬場(芝・ダート・障害)・グレード(G1〜G3・オープン・条件戦)がすべて異なり、同じ馬の「芝2000mの成績」と「ダート1800mの成績」は別物として扱う必要があります。
取得時の実装
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
def fetch_race_result(race_id: str) -> pd.DataFrame:
"""
netkeibaのレース結果を取得する
race_id例: '202506010211'(2025年06月01日・東京2R・11レース)
"""
url = f"https://db.netkeiba.com/race/{race_id}/"
headers = {"User-Agent": "Mozilla/5.0"}
res = requests.get(url, headers=headers)
res.encoding = "EUC-JP" # netkeibaはEUC-JPエンコード
soup = BeautifulSoup(res.text, "html.parser")
table = soup.find("table", class_="race_table_01")
# ... パース処理 ...
time.sleep(2) # サーバー負荷への配慮は必須
return df
競艇のデータ取得コードと比べて、エンコード処理・ID管理・条件の正規化など、前処理のコード量が1.5〜2倍程度になりました。
違いポイント②:特徴量の複雑さ(競馬は変数が多すぎる)
競艇の特徴量は「選手」「モーター」「レース環境」の3軸に整理できます。私の競艇AIでは最終的に423個の特徴量を使っていますが、カテゴリの区分けは明確です。
競馬の場合、変数の種類と相互作用が大幅に増えます。
競馬特有の主な特徴量
| カテゴリ | 主な変数例 | 競艇にあるか |
|---|---|---|
| 馬の能力 | 通算成績・距離別成績・前走タイム差 | 類似あり |
| 騎手 | 騎手の勝率・コース別成績・馬との相性 | 競艇では「選手」が直接対応 |
| 調教師 | 厩舎勝率・仕上がり状態の傾向 | なし |
| 血統 | 父・母父の距離適性・馬場適性 | なし |
| 馬体重 | 前走比増減・体重変化のトレンド | なし |
| 斤量 | 負担重量の相対値・斤量変化 | なし |
| 馬場状態 | 良・稍重・重・不良の各馬の成績 | 天候・風速で類似あり |
| ペース | 前半3F・後半3Fのラップタイム | なし |
血統情報の扱いが特に難しい。「この馬の父はディープインパクトで、母父はサンデーサイレンス」という情報が予測に効くことはわかっていても、それをどう数値化するか。私は最終的に「父ブランドの芝・ダート別勝率」を特徴量として使いましたが、これで十分なのかどうかは今も迷っています。
また、騎手と馬の相性は競艇にない概念です。同じ馬でも騎手が変わると成績が大きく変わる場合がある。騎手×馬のペア単位での過去成績を特徴量にしようとすると、サンプル数が少ない馬についてはほぼ機能しません。
私の競馬AIでは最終的に280個ほどの特徴量を使っています。競艇の423個より少ないですが、相互作用の複雑さと「サンプルが少ない変数が多い」という問題で、精度は競艇AIを下回っています。
違いポイント③:更新タイミング(オッズが直前に大きく動く)
競艇の場合、オッズはレース直前まで更新されますが、大きな動きが出るのは発走30〜60分前程度です。私の競艇AIは前日夜に特徴量を確定させて予測を出しており、オッズの最終値を取り込む設計にはしていません。それでも回収率96%程度が出ています。
競馬は違います。
競馬のオッズ動きの特徴
- 前日夜の想定オッズと当日直前オッズで大きく乖離することが多い
- 調教の出来・馬の状態・騎手変更など、当日朝の情報がオッズに反映される
- G1レースでは大口の馬券購入によって直前1〜2分でオッズが数%単位で動くことがある
競馬予測で「直前オッズを特徴量に入れるかどうか」は重要な設計判断です。入れると予測精度は上がりますが、前日予測ができなくなる。私は結局、直前オッズを特徴量に含めた「当日予測モデル」と、前日確定情報のみの「前日予測モデル」を両方作って使い分けています。
精度は当日予測モデルが明確に高い(単勝的中率32% vs 前日モデルの27%)。しかし当日モデルはレース30分前まで待つ必要があるため、運用のタイムラグが生まれます。
競艇AIではこういった「オッズの使い方」の設計に頭を悩ませた記憶がほとんどありません。競馬では、この点が地味に時間を取ります。
使ったライブラリとモデル
競艇AIとほぼ同じスタックを使いました。
# 主な依存ライブラリ
import lightgbm as lgb
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import accuracy_score, log_loss
import optuna # ハイパーパラメータチューニング
import pandas as pd
import numpy as np
モデルは LightGBM を使っています。競艇AIと同様です。競馬予測でもXGBoostやCatBoostを試しましたが、LightGBMが最も安定していました。
TimeSeriesSplit での交差検証は必須です。競艇AIを作ったときに「未来のデータが訓練に混入してしまう」という過学習パターンを経験していたので、競馬AIでは最初からTimeSeriesSplitを使いました。競艇AI開発の失敗が直接活きた部分です。
ハイパーパラメータは Optuna でチューニングしています。競艇AIより変数が多い分、チューニングに時間がかかります。
正直な精度と難易度の評価
現時点での競馬AIの数字です。
| 指標 | 競馬AI | 競艇AI |
|---|---|---|
| 単勝的中率 | 32% | 55% |
| 単勝回収率 | 81% | 96% |
| 開発期間 | 約4ヶ月 | 約6ヶ月 |
| 特徴量数 | 280個 | 423個 |
競馬の単勝的中率32%というのは、実は「ランダムより高い」水準ではあります。競馬の単勝は18頭立てなら理論的には5.5%が均等確率ですが、1番人気が平均30〜35%程度の的中率を持つため、「人気馬に乗っかっているだけ」に近い数字にもなりえます。
回収率81%はまだ赤字です。100円賭けると平均81円しか戻ってこない。競艇AIの回収率96%より明確に低く、実用レベルには到達していません。
難易度の正直な評価をするなら、競馬AIは競艇AIの1.5〜2倍の複雑さがあると感じています。データ取得・特徴量設計・モデル評価のすべてで、競艇より考えることが多い。
どちらから始めるべきか:競艇の方が初心者向けな理由
「公営ギャンブルAIを作ってみたい」という人が最初に取り組むなら、競艇を強く勧めます。理由は3つあります。
理由1:出走数が少なくデータ構造がシンプル
競艇は6艇で争うため、1レースのデータ量が少ない。競馬の18頭立てと比べて、1着予測の問題が格段にシンプルになります。特徴量の数も整理しやすく、「変数を増やしたら精度が上がった」という成功体験が早い段階で得やすい。
理由2:データの均質性が高い
競馬は距離・馬場・グレードの多様性があり、「条件ごとにモデルを分けるべきか」という設計判断が頻繁に発生します。競艇は同一水面・同一ルールで走るため、データの均質性が高く、単一モデルが機能しやすい。
理由3:オッズ設計がシンプル
前述のとおり、競馬では「直前オッズをどう使うか」という設計問題があります。競艇では前日情報だけでもある程度の予測ができる。「まずモデルを動かす」ことに集中できるのは競艇の方です。
競艇AIで一周してから競馬AIに挑戦する、というルートが開発体験として最もスムーズだと思います。私はその順番を踏めたので、競馬AIの開発中に「これは競艇と何が違うのか」を意識しながら学べました。
まとめ
競馬AIと競艇AIは、同じ「公営ギャンブルの予測AI」に見えて、開発上の難しさの質が大きく違います。
- データ取得:競馬は構造が複雑。netkeibaのEUC-JPエンコードや馬・騎手・調教師のIDを横断する設計が必要
- 特徴量の複雑さ:血統・斤量・騎手相性など競艇にない変数が多く、サンプルが少ない変数の扱いが難しい
- オッズの更新タイミング:競馬は直前オッズの動きが大きく、前日予測と当日予測の設計判断が必要
私の現時点の結論は「競艇AIは実用に近づいた、競馬AIはまだ研究段階」です。
競馬AIの回収率81%を100%超えまで持っていくのが今年の目標です。特徴量の改善余地はまだあると思っているし、アンサンブルも試していない。引き続き実験を続けます。
同じようにPythonで公営ギャンブルAIを作ろうとしている人の参考になれば嬉しいです。
*このブログでは競艇AI・競馬AI開発の実験記録を定期的に公開しています。Pythonと機械学習を題材に、エンジニアが副業・学習として取り組むAI開発の話を書いています。*
関連ツールを見る
この記事で紹介したツール・サービスをまとめてチェック。
![]()