競艇AIが展示前に5・6号艇を本命にした話|本命の的中率は12.9%に低下
このサイトで使っている予想AIは、作っている途中でおかしな本命を出していた。実際の1着率が6%ほどの5号艇と、3%ほどの6号艇を、本命に選ぶことが多かったのである。
きっかけは学習データの作り方の1行の誤りだった。結果が記録されていないレースを、「6艇全員が負けたレース」として覚えさせていた。ただ、その1行を直しただけでは終わらなかった(後半で書く)。
今のデータベースで、その誤りをわざと戻して作り直した。結論から言うと、誤りを戻したAIは、展示タイムが無い状態で予想させると本命の51.3%が5号艇、27.5%が6号艇になった。本命の的中率は12.9%まで落ちた。 展示タイムがある状態では、誤りの有り無しで成績はほとんど変わらない。だから全体の指標では気づけなかった。そして、誤りを直しても、回収率は100%に届かない。
結論: 同じAIでも、入力が欠けると的中率は56.6%から12.9%に落ちた
再現の条件は次のとおり。
- 学習: 2024-01-01〜2025-12-31 のレース
- 答え合わせ: 2026-01-01〜2026-10-26 の 46,213レース(検証期間)
- モデル: 今の予想AIと同じ特徴量・同じ設定の LightGBM(決定木をたくさん重ねて確率を出す機械学習の手法)
- 「展示なし」: 展示タイム・展示タイム順位・風速・波高の4列を空にして予想させた。締切前や前日、まだ展示が終わっていない時点の状態をまねている
| 作り方 | 推論時の入力 | 本命が1号艇 | 本命が5号艇 | 本命が6号艇 | 本命の的中率 | 単勝 本命1点の回収率 |
|---|---|---|---|---|---|---|
| 修正前(結果なし=全艇負け) | 展示なし | 12.2% | 51.3% | 27.5% | 12.9% | 67.5% |
| 修正後(結果なしは除く) | 展示なし | 77.7% | 2.4% | 3.0% | 52.9% | 88.2% |
| 修正前 | 展示あり | 92.1% | 0.3% | 0.1% | 56.6% | 90.8% |
| 修正後 | 展示あり | 92.0% | 0.3% | 0.1% | 56.6% | 90.9% |
| 直前4列を外して学習(今の前日予想の作り方) | ― | 93.9% | 0.2% | 0.1% | 56.1% | 90.2% |
| 1号艇を機械的に買う | ― | ― | ― | ― | 54.9% | 89.8% |

2026-01-01〜2026-10-26の検証期間の46,213レース。赤が「修正前のモデルが展示なしで本命に選んだ割合」、灰色が実際の1着率。5号艇の1着率は5.9%なのに本命の51.3%、6号艇の1着率は3.0%なのに本命の27.5%だった。
数で一番多かったのは5号艇(23,708レース)で、6号艇(12,710レース)が2番目だった。どちらも実際にはめったに勝たない枠である。
何が起きていたか: 結果の無いレースが1,970あった
2024-01-01〜2026-10-26 の158,724レースを数えると、出走表はあるのに結果が1行も無いレースが1,970あった(1.24%)。艇の行で数えると 951,841行のうち 11,796行(1.24%)である。
公式の成績ファイルを日ごとに開いて確かめると、内訳はこうだった。
- 1,958レース: 成績ファイルに「中止」と書かれている。1日12レースが丸ごと中止になった会場・日が106あった
- 12レース: 2026-05-16の尼崎。成績ファイルの尼崎の欄が空のままで、中止とも結果とも書かれていない
中止の理由はデータに無いので、ここでは数えていない。
なお、このプロジェクトの検証記録(docs/03_findings.md §5-1)と build.py のコメントは、これらを「成績ファイルが丸ごと欠落しているレース」と書いている。上の内訳は、今回成績ファイルを開いて「中止」の記載を数えた結果である。2つの書き方は食い違っているが、当時どのファイルを見てそう書いたのかは記録に無い。どちらが正しいかは、ここでは決めていない。
1行の誤り: 「データが無い」が「負け」になった
予想AIの学習では、1艇ごとに「1着だったか(1か0か)」を答えとして持たせる。修正前のコードは、着順を数字にしてから「1と等しいか」を見ていた。
結果の無いレースは、着順が全艇とも空(NaN、数値が無いことを表す値)になる。Python や pandas では、空の値を「1と等しいか」と比べると、答えは「いいえ」になる。だから結果の無いレースは、6艇とも「1着ではなかった」=0として学習に入った。
1レースには必ず1着がいる。全員が負けるレースは、現実には起きない。
学習期間(2024-01-01〜2025-12-31)には、結果が1行も無いレースが1,432あった。ほかに、全艇がフライングや失格で着順が付かなかったレースが4あった(202401040511 / 202503022303 / 202505010206 / 202512220905)。こちらは結果の行はあるが、着順の数字が無いので、同じく全艇0として学習に入っていた。合わせて1,436レース(1,432+4)を、「全員が負けたレース」としてAIに見せていたことになる。
今のコード(src/features/build.py の129〜139行)は、レースの中に着順が1つも無ければ、そのレースの答えを「不明」にして学習から外している。
has_result = df.groupby("race_id")["finish_rank"].transform(lambda s: s.notna().any())
df["is_win"] = pd.array([pd.NA] * len(df), dtype="Int64")
df.loc[has_result, "is_win"] = (df.loc[has_result, "finish_rank"] == 1).astype("Int64")
なぜ5・6号艇になるのか: 「展示が無い艇は勝たない」と覚えた
結果の無いレースは、着順だけでなく展示タイムも空になる。展示タイムは成績ファイルに載る値なので、成績が無ければ展示タイムも無い。成績ファイルから取る風速と波高も無い。
そのため修正前の学習データでは、展示タイムが空の行が9,890行あり、その1着率は0.0%だった。うち8,439行が、結果の無いレースから来ていた。AIから見ると、「展示タイムが無い艇は、1度も勝っていない」という強い規則がデータの中にあった。
そこへ、まだ展示が終わっていないレースを入れる。6艇とも展示タイムが空である。AIは6艇すべてを「勝たない側」に振り分けた。
- 修正前のモデルが展示なしで出した1着確率は、6艇の合計で平均0.06%だった(本来は合計100%前後になる)
- 展示ありなら、同じモデルの合計は平均99.1%である
全員がほぼ0%なら、その中の順番はほとんど意味を持たない。その「意味の無い順番」の1位が、5号艇や6号艇に偏った。なぜ5・6号艇に偏ったのか、その中身までは確かめていない。 測れたのは、展示なしでは1号艇の平均確率(0.009%)が5号艇(0.013%)や6号艇(0.012%)より低くなっていたことである。
誤りを直しても、展示なしで予想すると崩れる
ここで話は終わらなかった。誤りを直したモデルでも、展示なしで予想させると、本命の6号艇は、展示ありの0.14%から展示なしの2.97%へ約21倍に増えた。本命の的中率は52.9%で、1号艇を機械的に買う54.9%を下回った。
理由は同じ形をしている。直した後の学習データにも、展示タイムが空の行が1,451行残っていた。これは欠場や出遅れの艇で、やはり1着率0.0%である。数は7分の1に減ったが、「展示が無い艇は勝たない」という規則は残っていた。合計確率は平均1.17%で、まだ100%から遠い。
このサイトの記録(src/models/train_preday.py の冒頭、2026-08-30測定)にも同じ症状が残っている。当時は「本命が6号艇」が0.2%から3.1%へ15倍、本命の的中率は53.1%で、1号艇を機械的に買う54.3%を下回った。今回の再現(21倍)とは期間もレース数も違うが、向きは同じだった。
対策は、展示タイム・展示タイム順位・風速・波高の4列を最初から使わずに学習することだった。今の前日予想はこの作り方である。上の表のとおり、本命が1号艇の割合は93.9%、的中率は56.1%に戻る。
この作り方だと、修正前の誤り(結果なし=全艇負け)を残しても成績はほぼ同じだった(的中率56.2%・回収率90.2%)。今回の測り方の範囲では、誤りの害が出たのは「展示が空」の入力と重なったときだった。
展示がそろっていると、誤りは見えなかった
いちばん厄介なのはここである。展示ありで予想させると、修正前と修正後の成績はほぼ同じだった。
| 展示ありで予想 | 本命が1号艇 | 本命の的中率 | 単勝 本命1点の回収率 |
|---|---|---|---|
| 修正前 | 92.1% | 56.6% | 90.8% |
| 修正後 | 92.0% | 56.6% | 90.9% |

2026-01-01〜2026-10-26の検証期間の46,213レース。展示ありの2本は修正前後で同じ56.6%。大きく崩れたのは「修正前・展示なし」(12.9%)。「修正後・展示なし」も52.9%で、1号艇を機械的に買う54.9%を下回った。
過去のレースで成績を測ると、展示タイムは欠場の艇を除いてそろっている。だから過去データでの検証は合格する。崩れたのは、展示の4列を空にして予想させたとき(締切前や前日をまねたもの)だった。検証の数字が良くても、本番の入力が検証のときと同じ形とは限らない。
AI予想の回収率は、直しても100%に届かない
誤りを直すと、成績は「まともな水準」に戻る。ただ、その水準は100%の下である。

2026-01-01〜2026-10-26の検証期間の46,213レース。単勝の本命1点を100円ずつ買った回収率(払い戻し÷購入額)。いちばん良い「修正後・展示あり」でも90.9%。
- 修正後・展示あり: 90.9%
- 直前4列を外して学習: 90.2%
- 1号艇を機械的に買う: 89.8%
モデルと1号艇を買うだけの差は、0.4〜1.0ポイントしかない。この記事が直したのは「明らかにおかしい本命」であって、儲かる予想ではない。
当時の記録との関係
当時の記録(docs/03_findings.md §5-1 と、build.py の「2026-08-28実測」というコメント)は「1,811レース・10,866行・学習データの1.35%」としている。今のデータベースで数え直すと、2024-01-01〜2026-10-26 で1,970レース・11,796行・1.24%である。
- レース数が増えたのは、主に期間が延びたためである。2026-08-28以前に限ると、今は1,898レース
- 割合が下がったのは、分母が増えたためと考えられる。2026-08-31に出走表の読み込み漏れを直し、9,264レースが戻った(
docs/03_findings.md§5-6)。直す前に取っておいた退避コピーで2026-08-28以前を数えると、割合は1.35%で当時と同じになる - ただし、その退避コピーでもレース数は1,894で、当時の1,811とは合わない。1,811という数そのものは再現できなかった
当時の記録には「6号艇(実際の1着率3.1%)が本命27.7%で選ばれていた」ともある。今回の再現は27.5%で近いが、当時の測り方(どのレースを対象にしたか)は記録に残っていない。同じ測り方での一致とは言えない。
測り方の詳細数え方と対象の決め方。読まなくても本文の結論は変わりません
- データ: 自前のデータベース(公式の番組表・競走成績を取り込んだもの)。集計の終端は2026-10-26。
- 結果の無いレース: 出走表(
race_entry)にあって、着順の表(race_result)に1行も無いレース。中止かどうかは、公式の成績ファイルの「中止」の記載で日ごとに照合した。 - モデル: 今の予想AIと同じ特徴量(枠・級別・勝率・モーター・展示タイム・直近の成績など)と同じ設定の LightGBM。乱数の種も同じ。4通り(修正前/修正後 × 直前4列あり/なし)を同じ学習期間で作った。
- 本命: 1レースの中でモデルの1着確率がいちばん高い艇。同じ値なら内側の枠。
- 展示なし: 展示タイム・展示タイム順位・風速・波高を空にして予想させた。
- 回収率: 単勝の払い戻し÷購入額。1レース100円。単勝の払い戻しが記録されていないレースは、外れとして数えた。
- 確かめていないこと: 修正前のモデルが5・6号艇に偏った理由。中止の理由。当時の1,811レースの数え方。結果の無いレースが「中止」か「成績ファイルの欠落」か、検証記録との書き方の違い。
- 集計のスクリプトと結果は計算ログ(
articles/_work/b3_calc.md)に残した。
まとめ
- 結果の無いレースが1,970あった: 2024-01-01〜2026-10-26 の158,724レースのうち1.24%。成績ファイルでは、ほぼすべてに「中止」の記載があった(検証記録は「成績ファイルの欠落」と書いており、どちらが正しいかは決めていない)。
- それを「全艇負け」と覚えると: 展示なしで予想させたとき、本命の51.3%が5号艇、27.5%が6号艇になった。的中率は12.9%。
- 原因の形: 「展示タイムが空の艇は勝たない」という規則を学んでいた。展示前のレースでは6艇とも空なので、全員がほぼ0%になった。
- 直しただけでは足りない: 欠場の艇が同じ規則を残す。展示なしだと本命の6号艇は約21倍。展示の4列を使わずに学習して、ようやく戻った。
- 過去データの検証では見えない: 展示ありなら、修正前後とも的中率56.6%で同じだった。
- 直しても100%未満: 単勝 本命1点の回収率は90.2〜90.9%。1号艇を買うだけで89.8%。
AIの予想がおかしいとき、疑うべきはモデルより先に、学習データの答えの作り方と、本番で入る入力の形だった。
免責
- 本記事に記載した数値はすべて過去データに対する実測であり、将来の的中や利益を保証するものではありません。
- 本記事および言及したツールは分析の補助を目的としており、舟券の購入を勧誘するものではありません。
- 舟券は20歳未満の方は購入できません。
- 舟券の購入は自己責任で、生活に必要な資金とは別の、余裕資金の範囲で行ってください。のめり込みには十分ご注意ください。