0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「京都だけ壊れた」原因を95.6%の馬で測定した結果  ── venue_correction.csv は「本命を当てる」より「3連複を組む」補正だった ── シリーズ第四弾

0
Last updated at Posted at 2026-05-31

「京都だけ壊れた」原因を95.6%の馬で測定した結果

── venue_correction.csv は「本命を当てる」より「3連複を組む」補正だった ── シリーズ第四弾

Python / アルゴリズム / データ分析 / 機械学習 / 競馬AI


対象期間:2026年5月24日〜5月31日 制作者:yuji


このシリーズについて

V1:作った
V2:検証した
V3:「ローテーション補正はノイズだった」
V4:「ダークマター係数を実装したら京都だけ壊れた」
V5:「壊れた理由を、実際のレース結果で測定した」

V4記事は投稿2.5時間で92ビューを記録した。あの記事で書けなかったことがある。なぜ京都だけ壊れたかを、数字で証明すること。 V5はその答えを出すフェーズだ。

71歳・隠居・Ubuntu・競馬AI。今回も変わらない。変わったのは補正値の作り方だ。


V3・V4との違い:補正の作り方が逆転した

期間 読者が覚えること 補正の作り方
V3 ローテーション補正はノイズだった 仮説 → 実装 → 検証
V4 京都だけ壊れた 仮説 → 実装 → 検証
V5 補正値をデータから作るようになった 結果 → 分析 → 係数算出 → 検証

順序が逆転した。これがV5の本質だ。

V3・V4では「こうなるはず」という仮説を先に立てて実装していた。V5からは「実際にどうなったか」というデータを先に集め、そこから係数を逆算している。半導体製造ラインの品質管理と同じ思想——データが出てから判断する


V5期間の核心実装:venue_correction.csv の自動設計

venue_correction.csv とは何か

競馬場 × 騎手ランク(S/A/B/C)の組み合わせごとに補正係数を持つCSVファイルだ。「ダークマター係数(場*C)」と「騎手ランク係数」を統合した補正テーブル。

会場,ダークマター,ランクS,ランクA,ランクB,ランクC
東京,1.025,1.028,0.700,1.212,0.815
京都,0.896,1.048,1.244,0.700,0.788

V4期間はこれを手書きで編集していた。それが事故の温床だった。

No.26:hosei_mixer への venue_correction 設計モード追加

V5最大の実装はこれだ。

def auto_scan_venue(self):
    """
    MIXER_INPUT_DIR_KAKUTEIの全hikaku xlsxを走査し
    競馬場×騎手ランク別の乖離率を自動集計して
    係数推奨値を算出する
    """
    files = list(Path(MIXER_INPUT_DIR_KAKUTEI).glob("*.xlsx"))
    print(f"走査対象: {len(files)}")
    
    venue_stats = defaultdict(lambda: defaultdict(list))
    valid_count = 0
    
    for f in files:
        try:
            df = self._load_hikaku_sheet(f)
            if df is None:
                continue
            valid_count += 1
            self._aggregate_venue_rank(df, venue_stats)
        except Exception:
            continue
    
    print(f"有効データ: {valid_count}")
    return self._calc_recommendations(venue_stats)

487件のhikaku xlsxを自動走査、481件有効(98.8%成功率)。

手書きCSV編集という危険な作業を完全に廃止した。basho_correction_seiki/kensyou.csv(全場1.000で形骸化していた)も同時に廃止。メニュー構成・自動集計ロジック・廃止処理まで一気通貫で設計・実装した。

No.27:_get_jockey_rank_map バグの発見と修正

No.26の初動実行で即座にバグを発見した。

症状: 487件走査・481件有効を確認。ダークマター係数は正常集計されたが、ランクS/A/B/Cが一切表示されない。

原因:

# バグのあったコード(No.26)
def _get_jockey_rank_map(self, wb):
    # 「予想結果」シートを探していた
    if "予想結果" not in wb.sheetnames:
        return {}  # ← 常にここで空を返していた

実際のhikaku xlsxは「完全比較」シート1枚構成。「予想結果」シートは存在しないためrank_mapが常に空{}となり、ランク集計がゼロのまま推奨係数が表示されなかった。

修正(No.27):

# 修正後:_get_rank_map_from_hikaku()を新設
def _get_rank_map_from_hikaku(self, wb):
    # 「完全比較」「比較」を含むシートを優先して探す
    target_sheet = None
    for name in wb.sheetnames:
        if "完全比較" in name or "比較" in name:
            target_sheet = wb[name]
            break
    
    if target_sheet is None:
        return {}
    
    # そのシート内の「騎手ランク」列から {馬名: ランク} を取得
    rank_map = {}
    headers = [cell.value for cell in target_sheet[1]]
    rank_col = headers.index("騎手ランク") if "騎手ランク" in headers else None
    
    if rank_col is None:
        return {}
    
    for row in target_sheet.iter_rows(min_row=2, values_only=True):
        horse_name = row[0]
        rank = row[rank_col]
        if horse_name and rank:
            rank_map[horse_name] = rank
    
    return rank_map

「動いているように見えたが実は集計ゼロだった」——V4の「設計と実装のズレを深夜3時に発見した」と同じパターンだ。確認文化がなければ見落としていた。


実戦検証:46レースで測定した

検証設計

項目 内容
検証期間 2026/05/29(土)〜 05/31(月)
対象レース 東京・京都 各23R、計46R
比較対象A seiki_v5.py(venue_correction.csv なし
比較対象B reisugo_v58.py(venue_correction.csv あり
検証指標 ◎1着的中率・3着内率・上位3頭含有率・場*C変化量

主要KPI

指標 seiki(補正なし) reisugo(補正あり)
◎1着的中(46R) 13/46 28.3% 10/46 21.7% −6.6pt
◎3着内(46R) 23/46 50.0% 20/46 43.5% −6.5pt
◎5着内(46R) 29/46 63.0% 27/46 58.7% −4.3pt
上位3頭に1着馬(46R) 19/46 41.3% 20/46 43.5% +2.2pt
場*C影響馬数(2日計) 656/686頭(95.6%

◎1着的中率はseikiが優位。しかし「上位3頭に1着馬が含まれる率」はreisugoが上回った。

3連複の観点では、補正ありのreisugoが有利だ。これが今回の最重要示唆だ。補正は「本命を当てる精度」より「3連複を組む精度」を上げる方向に機能している。


最重要発見①:場*C中央値が2日間完全一致した

指標 5/29(土) 5/31(月) 評価
場*C平均変化(全体) −0.167 −0.151 下方偏重は再現
場*C中央値 −0.260 −0.260 2日間完全一致 → 構造的
東京 場*C平均変化 −0.090 −0.059 5/31で縮小
京都 場*C平均変化 −0.240 −0.267 5/31でさらに拡大
場*C変化馬数 331/348(95.1%) 325/338(96.2%) 全域カバーで一貫

中央値−0.260が2日間完全一致。これは偶発ではなく構造的な特性だ。

686頭中656頭(95.6%)に補正が影響している。venue_correction.csvは「一部の馬だけ補正する」のではなく、ほぼ全馬の指数を動かしているということだ。


最重要発見②:京都と東京は構造的に別物だった

競馬場別3着内率

seiki 3着内 reisugo 3着内 評価
東京(23R) 48% 39% seiki優位 ⚠️
京都(23R) 39% 48% reisugo逆転 ✅

京都では補正が機能し、東京では補正が逆効果だった。

場*C平均変化で見ると、京都は東京の2.5〜4.5倍の変動幅がある。2日連続でこのパターンが再現された。venue_correction.csvの京都補正の強さは偶発ではない。

  • 京都での◎変更19件:reisugo 5勝 / seiki 2勝
  • 東京での◎変更(東京12R・4R・6R):seikiがすべて1着

東京の補正係数は現時点で過剰と判断せざるを得ない。

クラス別でも違いが出た

クラス seiki 3着内 reisugo 3着内 評価
未勝利(17R) 59% 65% reisugo優位
1勝クラス(10R) 50% 30% seiki優位
2勝クラス(4R) 25% 25% 同率
特別/重賞(15R) 27% 33% reisugo優位

未勝利と重賞でreisugoが優位、1勝クラスでseikiが優位。係数のクラス適合に偏りがある。 これは次の課題だ。


最重要発見③:ランクBへの −46.2% ペナルティが完全に逆効果だった

05/26の係数修正(再確認)

ランク 変更前 変更後 変化率 方向の根拠 実際の結果
S(川田・ルメール等) 0.762 1.048 +37.5% 乖離率0.54 > 基準0.411 方向正 ✅
A(岩田望・横山和等) 0.750 1.244 +65.9% 乖離率0.59 > 基準0.443 幅過大の疑い ⚠️
B(武豊・三浦等) 1.300 0.700 −46.2% 乖離率0.20 < 基準0.400 逆効果確認 ❌
C(大多数) 1.054 0.788 −25.2% 乖離率0.58 < 基準0.611 要継続観察

seikiのランクB◎:1着的中75%、3着内100%(4R)。

武豊・三浦皇成・松若風馬・鮫島駿。これだけの実績騎手の馬を−46.2%でペナルティすれば、当然指数が不当に下がる。V5期間の事前分析でも「Bランクへの+10%ブーストが過剰」と判断していたが、係数修正で逆方向に振りすぎた。

N=4のため断定はできないが、方向として逆効果は明白だ。


週明け検証:事前設定した懸念の答え合わせ

検証対象 事前懸念 実着順 判定 解釈
京都1R マクローリン ランクA+65.9% → 11番人気◎ 7着 過剰上昇確認 ランクA過学習
京都12R カワキタマナレア 同上 → 11番人気◎ 2着 3着内的中 低人気馬の好走。一部有効性あり
京都3R ワルトシュタイン 同上 → 13番人気◎ 3着 3着内的中 補正が実力を捉えた可能性
京都12R ブルクトーア 同上 → 10番人気◎ 7着 過剰上昇確認 懸念が的中
東京8R アバンデル データ解禁 指数0→13.82 2着 圏外で好走 seikiでは無効化。データ解禁問題は実際に影響あり
東京11R ショウナンガルフ データ解禁 指数0→10.90 17着 両者外れ データ解禁が必ずしも有効でないことも確認

ランクA過剰上昇:4件中2件的中・2件外れ。「過学習」とも「本物の補正」とも言い切れない結果。

これが正直なところだ。追加サンプルが必要。N≧10になった時点で再評価する。


総合評価

取り組み 判定 有効度 コメント
venue_correction.csv の有意差 ✅ 確定 95.6%の馬に影響。補正の存在意義は明確
京都の補正(場*C中央値一致) ✅ 確定 2日完全一致で構造的再現性確認
京都補正(05/26修正後) ✅ 達成 3着内率で明確に改善(39%→48%)
未勝利クラスでのreisugo優位 ✅ 確認 ダークマター補正が未勝利馬の実力差を捉えやすい
3連複軸としての上位3頭精度 ✅ 確認 ◎不変レースで48.1%(vs seiki 40.7%)
東京補正 △ 要見直し ◎変更が裏目多数。現状は補正なしの方が良い
騎手ランクA係数(+65.9%) △ 保留 低人気馬の好走例あり。過剰上昇も同数で保留
騎手ランクB係数(−46.2%) ❌ 要再検討 N=4で3着内100%。逆効果の疑いが強い
S・Aランク騎手の◎選出増加 ✅ 達成 2日連続でODT目的(1番人気への集中緩和)を確認

V6期間への引き継ぎ:次の3手

最高優先度(緊急)

ランクB係数を 0.700 → 0.90〜0.95 に緩和。
N=4でも逆効果が示された。判断基準:N≧10でランクB 3着内率が改善傾向を確認するまで継続。

高優先度

東京S/A係数を1.0付近に抑制。
東京◎変更レースでreisugoが5割以上勝利するまで補正を絞る。段階的な緩和が現実的だ。

高優先度

ランクA係数を段階適用(0.75 → 0.95 → 1.244)またはBayesian収縮で幅を抑制。
N=25でのサンプル推定値として+65.9%は変化幅が大きすぎる。小標本問題への対処が必要だ。


このプロジェクトで守り続けているルール

V1から変わっていないものがある。

# V5期間 確定コーディングルール(V4より継続 + 1件追加)

① 修正のたびNo.XX採番・省略禁止
② 冒頭コメントはgrepで実コード照合してから更新
③ py修正後はscan_dependencies.py実行
④ バッチフォルダ更新時は _batch_dirs 同時更新(絶対ルール)
⑤ 新CSV導入前に「全馬一律乗算では順位に影響しないか」確認
⑥ 作業前に必ず確認する──「取り掛かっていいですか?」(V5追加)

⑥はこの一言から生まれた。

「会議で知ってるふりして確認もしないで、あとでドツボにハマりそうになったことあるからね。重要なのは経験済み」

半導体製造業の経験則だ。表面上動いているように見えても、深く確認することで設計と実装のズレを発見できる。No.27の「完全比較シート問題」も、⑥がなければ見落としていた。


おわりに:V5で読者に覚えてほしいこと

補正値を感覚ではなく結果から作るようになった。

V3では「ローテーション補正はノイズだった」と学んだ。
V4では「京都だけ壊れた」と学んだ。
V5では「壊れた理由をデータで測定し、次の修正を設計した」。

46レースの検証で分かったことは3つだ。

  1. 補正の方向性は正しい(95.6%の馬に影響・京都3着内率逆転)
  2. 係数の幅が大きすぎる(特に東京・ランクB)
  3. 3連複軸としてはreisugoが有利(上位3頭含有率+2.2pt)

次回はこの3点を修正してV6検証に臨む。


競馬データ解析プロジェクト 変革履歴レポート V5
対象期間:2026年5月24日〜5月31日 制作者:yuji
V3記事 → V4記事 → 本記事(V5)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?