結論:競艇AIで最初に詰まるのは「データ収集」「特徴量設計」「過学習」の3つ
先に結論からお伝えすると、競艇AIを自作しようとした初心者がほぼ確実に詰まるのは次の3つです。
- データ収集:公式サイトのHTML構造が独特で、スクレイピングが想像以上に大変
- 特徴量設計:オッズ・選手成績・モーター情報のどれを優先すべきか判断できない
- 過学習:ローカルでは精度が出るのに、実レースではまったく当たらない
私自身、平日夜と週末を使って3ヶ月ほど開発を続けてきましたが、この3つのどれかで必ず1週間以上は止まりました。本記事では、会社員エンジニアの私が実際にやってみた失敗と学びを正直に共有します。これから競艇AIを作りたい人、機械学習の題材を探している人の参考になれば嬉しいです。
開発のきっかけ:なぜ会社員エンジニアが競艇AIに手を出したのか
きっかけは単純で、「Pythonと機械学習の勉強を、何か面白いお題でやりたかった」だけです。Kaggleのチュートリアルは何度かやりましたが、どうしても手が動かなくなる。やはり自分が興味を持てる題材じゃないと続きません。
私の場合、もともと友人と年に数回ボートレース場に行く程度のライトな競艇ファンでした。データの量も豊富で、出走表・結果・オッズ・モーター成績など、ほぼすべてが公式サイトから無料で取れる。教材としてこれ以上ない題材だと感じたわけです。
利用したスタックは概ねこんな構成です。
- 言語:Python 3.11
- データ取得:requests + BeautifulSoup4
- データ処理:pandas、numpy
- モデル:LightGBM、scikit-learn
- 環境:MacBook Air M2(ローカル開発のみ)
「儲けたい」というよりは「機械学習を実データで一周してみたい」が動機でした。結果として儲かってはいないですが、学びは想像の3倍ありました。
詰まりポイント①:公式サイトのデータ取得で1週間溶かした話
最初の壁は、いきなりモデル開発ではなくデータ収集でした。
ボートレース公式サイト(boatrace.jp)は無料で過去のレース結果が見られますが、HTML構造が独特で、テーブルのclass名が日付ごとに微妙に違ったり、文字コードがShift_JISベースだったりします。私は最初、雑にBeautifulSoupでパースしようとして、3日ほど「なぜか半角スペースが取れない」「選手名と登録番号の区切りが行ごとに違う」といった問題で詰まりました。
最終的にうまくいった工夫は次のとおりです。
- リクエスト間隔は最低1秒以上空ける(サーバー負荷への配慮は必須)
- HTMLをいったんローカルに全保存してからパースする(再実行コストを下げるため)
- 出走表・結果・オッズの3種類は別スクリプトに分離する
過去2年分のデータを取り終わるまでに、概算で1週間ほどかかりました。「機械学習の勉強」のはずが、ひたすらXPathとencoding問題と格闘していた1週間です。ここは想定の2倍は時間がかかると見ておくのが安全です。
詰まりポイント②:オッズと選手成績、どの特徴量が効くのか分からない問題
データが集まると、次に直面するのが「何を特徴量にするか」問題です。競艇には公開されているデータが大量にあります。
- 選手の全国勝率・当地勝率
- モーター2連率・ボート2連率
- 直近6ヶ月のスタートタイミング
- 進入予想・コース別1着率
- 当日のオッズ(単勝・複勝・2連単・3連単)
正直に言うと、最初は「全部入れればいいだろう」と思って50個以上の特徴量を突っ込みました。結果、モデルの精度が逆に下がるという、教科書どおりの失敗をしました。
そこから少し手戻りして、相関係数とLightGBMのfeature_importanceを見ながら絞り込みました。私のケースで効いたのは、ざっくり次の順です。
- オッズ(特に2連単オッズ)
- 選手の当地勝率(その競艇場での勝率)
- モーター2連率
- 進入コース
逆にあまり効かなかったのは、過去のG1優勝歴のような「レアイベント系」の特徴量でした。データが少なすぎてノイズになりがちです。「とりあえず突っ込む」より「仮説を立てて1つずつ追加する」ほうが結果的に早いと痛感しました。
詰まりポイント③:精度80%のモデルが本番で全く当たらなかった理由(過学習の罠)
ここが一番つらかったポイントです。
学習データで交差検証すると、3連単の的中率が「概算で20%」「単勝で80%近く」という、見るからに怪しい数字が出ました。最初は「よっしゃ勝った」と思いましたが、直近1ヶ月のデータでテストすると、的中率はガクンと落ちて単勝で40%台。3連単に至ってはほぼ当たりません。
原因を分解していくと、典型的な過学習でした。具体的には次の点が問題でした。
- 時系列を無視してランダム分割していた:未来のデータが学習側に混ざり、リーク(leakage)を起こしていた
- オッズを特徴量にしていたのに、結果が出た後のオッズも一部混ざっていた:これも実質的なリーク
- 特定の競艇場のデータが多く、他競艇場で精度が出なかった
対策としては、TimeSeriesSplitを使い、必ず「過去のデータで学習 → 未来のデータで評価」する形に変えました。それだけでテスト精度は単勝50%台まで現実的な数字に落ち着き、逆に信頼できる指標になりました。
機械学習の教科書には「リークに気をつけろ」と必ず書いてありますが、自分でやると本当に踏みます。一度踏むと二度と忘れません。
3ヶ月運用して見えた現実:的中率と回収率の正直な数字
3ヶ月間、毎日少額(1日500円程度)で実際に賭けてみた結果を正直に書きます。あくまで個人の概算ですが、こんな感じでした。
- 単勝的中率:約45%(人気どおり買ってもこの程度なので、優位性は薄い)
- 3連単的中率:約3%(買い目を絞ると更に下がる)
- 回収率:概算で70〜80%(控除率25%を考えると、ほぼ平均的な負け方)
率直に言って、「AIで競艇に勝つ」のは個人開発レベルでは相当厳しいです。控除率25%という壁は重く、これを超える優位性をモデルが持てるかと言われると、現状の私のモデルでは無理でした。
ただし、学びの観点では大きな黒字です。データ収集・特徴量設計・モデル評価・運用後の振り返りという、機械学習の一連のサイクルを実データで一周できたことは、業務でAI関連の話が出たときの引き出しを確実に増やしてくれました。
これから競艇AIを作る人へ:最初にやるべき3ステップと避けるべき罠
最後に、これから始める人に向けて、私が遠回りした分のショートカットをまとめます。
最初にやるべき3ステップ:
- 小さく始める:いきなり3連単を狙わず、まずは「1着になる選手を当てる二値分類」から始める
- 時系列でデータを分ける:必ず
TimeSeriesSplitか手動で過去/未来を分割する - ベースラインを先に作る:「人気1番手をそのまま買う」場合の的中率・回収率を出して、それを超えられるかを基準にする
避けるべき罠:
- 過去データで90%超えた、と喜ばない(ほぼ確実にリークしている)
- 特徴量を増やせば精度が上がると思わない(多くの場合、ノイズが増えるだけ)
- 「儲け」を目的にしない(控除率25%の前提で、勝てる確率は極めて低い)
競艇AIは儲けの観点ではコスパが悪いですが、機械学習の総合演習としては最高の題材です。題材選びに迷っている個人開発エンジニアには、本気でおすすめしたいと思います。
まとめ
競艇AI開発で最初にぶつかるのは、データ収集・特徴量設計・過学習の3点。私自身、それぞれで1週間以上の手戻りを経験しました。儲けは出ていませんが、機械学習の一連の流れを実データで体験できたことは、本業のITエンジニアとしての経験値を確実に底上げしてくれています。
これから始める方は、ぜひ「単勝の二値分類 → 時系列分割 → ベースライン比較」の順で、小さく回してみてください。私の3ヶ月分の遠回りが、誰かの1ヶ月の節約になれば幸いです。
関連ツールを見る
この記事で紹介したツール・サービスをまとめてチェック。
![]()