Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

2021年有馬記念を予想する

Last updated at Posted at 2021-12-22

#はじめに
この記事は、SLP KBIT AdventCalendar2021 23日目の記事です。

今年某コンテンツのおかげで競馬にハマり、高松宮記念から競馬を見始めたのですが、好きになった馬が続々と引退していってしまい少し悲しいです。12/26(日)に行われる有馬記念でも引退を表明した名馬が2頭います。 キセキ クロノジェネシス です。キセキは2017年の菊花賞以降勝利がないですが、重賞でも十分馬券圏内に入っており、引退レースでも是非とも馬券に絡んでほしいですね。現役最強との呼び声高いクロノジェネシスは今年凱旋門賞にも出走しました。前人未到のグランプリ4連覇に期待がかかります。

そして、女王クロノジェネシスに挑む有力馬が、 エフフォーリア タイトルホルダー ステラヴェローチェ アリストテレス アカイイト です。中でも、エフフォーリアはコントレイルグランアレグリアといった古馬の中でもトップクラスの実力を持つ2頭を相手に天皇賞・秋で完勝しています。

今年を締めくくるのにふさわしい顔ぶれとなったグランプリ有馬記念ですが、我々にとっては予想を立てる上でデータの収集が必要となってきます。そんなデータの収集をPythonを用いて便利にできないか、というのがこの記事の内容です。

#まず何をするのか?
まずは去年までのデータを集めないことには話になりません。
2020~2006年までの15年間の有馬記念のレース結果をpandasとBeautifulSoupを用いてスクレイピングしていきます。
netkeiba様からスクレイピングを行っていきます。
コードは下のようになります。

race_results.py
import pandas as pd
import time
from tqdm import tqdm
import requests
import re
from bs4 import BeautifulSoup

class Results:
    @staticmethod
    def scrape(race_id_list):
    #netkeibaのデータベースで使われている レースID からレース情報を取得

        race_results = {}
        #レース結果を入れる関数

        for race_id in tqdm(race_id_list):
            time.sleep(1)
            try:
                url = "https://db.netkeiba.com/race/" + race_id
                df = pd.read_html(url)[0]

                html = requests.get(url)
                html.encoding = "EUC-JP"
                soup = BeautifulSoup(html.text, "html.parser")

                horse_id_list = []
                horse_a_list = soup.find("table", attrs={"summary": "レース結果"}).find_all("a", attrs={"href": re.compile("^/horse")})
                for a in horse_a_list:
                    horse_id = re.findall(r"\d+", a["href"])
                    horse_id_list.append(horse_id[0])
                df["horse_id"] = horse_id_list
           
                df.index = [race_id] * len(df)

                race_results[race_id] = df
            except IndexError:
                continue
            except AttributeError:
                continue
            except Exception as e:
                print(e)
                break

        race_results_df = pd.concat([race_results[key] for key in race_results])
        race_results_df.to_pickle('results.pickle')
        #一度スクレイピングした情報をpickleファイルに保存

        return race_results_df

ちなみに、2020年の物をスクレイピングした結果はこのようになります。

arima2020.txt
              着順  枠番  馬番         馬名  性齢  斤量    騎手     タイム     着差     単勝    人気       馬体重       調教師    horse_id
202006050811   1   5   9   クロノジェネシス  牝4  55  北村友一  2:35.0    NaN    2.5   1.0  474(+10)  [西] 斉藤崇史  2016104750
202006050811   2   7  14       サラキア  牝5  55  松山弘平  2:35.0     クビ   74.9  11.0   448(-2)   [西] 池添学  2015104793
202006050811   3   7  13    フィエールマン  牡5  57  ルメール  2:35.1     クビ    3.5   2.0    478(0)  [東] 手塚貴久  2015105075
202006050811   4   4   7  ラッキーライラック  牝5  55  福永祐一  2:35.5  2.1/2    8.1   4.0    522(0)  [西] 松永幹夫  2015105046
202006050811   5   3   5   ワールドプレミア  牡4  57    武豊  2:35.6    1/2   13.5   5.0   484(+2)  [西] 友道康夫  2016104854
202006050811   5   5  10  カレンブーケドール  牝4  55  池添謙一  2:35.6     同着    7.9   3.0   478(+4)   [東] 国枝栄  2016105089
202006050811   7   4   8   ペルシアンナイト  牡6  57  大野拓弥  2:35.6    アタマ  148.1  12.0    500(0)  [西] 池江泰寿  2014105258
202006050811   8   2   3  クレッシェンドラヴ  牡6  57  坂井瑠星  2:35.8  1.1/2  188.1  16.0    500(0)    [東] 林徹  2014104386
202006050811   9   8  15    オセアグレイト  牡4  57  横山典弘  2:35.9     クビ  183.4  15.0   494(-2)  [東] 菊川正達  2016101209
202006050811  10   2   4  ラヴズオンリーユー  牝4  55  M.デム  2:35.9     クビ   15.5   6.0   480(-6)  [西] 矢作芳人  2016104648
202006050811  11   8  16  ユーキャンスマイル  牡5  57  岩田康誠  2:36.4      3    157  13.0   504(+6)  [西] 友道康夫  2015105032
202006050811  12   3   6        キセキ  牡6  57   浜中俊  2:36.5    1/2   24.9   8.0   516(+8)  [西] 角居勝彦  2014101976
202006050811  13   1   1       バビット  牡3  55  内田博幸  2:36.8      2   36.2  10.0   458(+8)  [西] 浜田多実  2017103000
202006050811  14   6  12     オーソリティ  牡3  55  川田将雅  2:37.0      1   20.3   7.0   514(+2)  [東] 木村哲也  2017105649
202006050811  15   6  11      モズベッロ  牡4  57  田辺裕信  2:38.2      7  174.6  14.0  470(-10)  [西] 森田直行  2016100915
202006050811   中   1   2  ブラストワンピース  牡5  57  横山武史     NaN    NaN   33.1   9.0   546(-4)  [東] 大竹正博  2015104882

一番左に表示されている数字列は2020年の有馬記念のレースIDです。
同様に、2006年から2019年までのレースIDを用いてスクレイピングしていきます。

#次に
15年分のレース結果が集まったので、ここからは勝ち馬の予想につなげていきます。掲示板に表示される上位5頭の特徴を調べるべく、前走までのデータを収集していきます。

コードは以下のようになります。

get_data.py
from tqdm import tqdm
import time
import pandas as pd

class HorseResults:
    @staticmethod
    def scrape(horse_id_list):
    #それぞれの年で上位5頭になった馬のリスト

        horse_results = {}
        for horse_id in tqdm(horse_id_list):
            try:
                url = 'https://db.netkeiba.com/horse/' + horse_id
                df = pd.read_html(url)[3]
                #受賞歴がある馬の場合、3番目に受賞歴テーブルが来るため、4番目のデータを取得する
                if df.columns[0]=='受賞歴':
                    df = pd.read_html(url)[4]
                df.index = [horse_id] * len(df)
                horse_results[horse_id] = df
                time.sleep(1)
            except IndexError:
                continue
            except Exception as e:
                print(e)
                break
            except:
                break
     
        horse_results_df = pd.concat([horse_results[key] for key in horse_results])
        horse_results_df.to_pickle('horse_results.pickle')

        return horse_results_df

2020年有馬記念勝ち馬のクロノジェネシスでの出力は以下のようになります。

horse_results.txt
2016104750  2021/10/03   ロンシャ  NaN   NaN            凱旋門賞(G1) NaN  14.0  NaN   7    4.8   3.0      7  マーフィ  58.0  芝2400  重  NaN      NaN  NaN   NaN          NaN        NaN   NaN        計不     NaN NaN            NaN      NaN
2016104750  2021/06/27   3阪神4    晴  11.0            宝塚記念(G1) NaN  13.0  5.0   7    1.8   1.0      1  ルメール  56.0  芝2200  良   **   2:10.9 -0.4    **      4-4-3-4  35.1-34.7  34.4    478(0)     NaN NaN    (ユニコーンライオン)  15281.4
2016104750  2021/03/27   メイダン  NaN   NaN      ドバイシーマクラシッ(G1) NaN   9.0  NaN   9    1.9   1.0      2  北村友一  55.0  芝2410  良  NaN      NaN  NaN   NaN          NaN        NaN   NaN        計不     NaN NaN            NaN      NaN
2016104750  2020/12/27   5中山8    晴  11.0            有馬記念(G1) NaN  16.0  5.0   9    2.5   1.0      1  北村友一  55.0  芝2500  良   **   2:35.0  0.0    **    12-12-3-3  30.8-36.6  36.2  474(+10)     NaN NaN         (サラキア)  30340.2
2016104750  2020/11/01   4東京8    曇  11.0          天皇賞(秋)(G1) NaN  12.0  6.0   7    4.4   2.0      3  北村友一  56.0  芝2000  良   **   1:57.9  0.1    **        8-9-9  36.5-33.6  32.8    464(0)     NaN NaN        アーモンドアイ   3836.0
2016104750  2020/06/28   3阪神8    曇  11.0            宝塚記念(G1) NaN  18.0  8.0  16    4.1   2.0      1  北村友一  56.0  芝2200  稍   **   2:13.5 -1.0    **      7-8-7-1  34.6-36.3  36.3  464(+10)     NaN NaN          (キセキ)  15378.0
2016104750  2020/04/05   2阪神4    晴  11.0             大阪杯(G1) NaN  12.0  8.0  12    5.2   4.0      2  北村友一  55.0  芝2000  良   **   1:58.4  0.0    **      3-3-3-3  36.9-34.2  34.0   454(-6)     NaN NaN      ラッキーライラック   5474.4
2016104750  2020/02/16   2京都6    雨  11.0            京都記念(G2) NaN   9.0  7.0   7    2.7   1.0      1  北村友一  54.0  芝2200  重   **   2:16.4 -0.4    **      3-3-3-3  36.8-36.9  35.8  460(+12)     NaN NaN    (カレンブーケドール)   6270.0
2016104750  2019/11/10   5京都4    晴  11.0        エリザベス女王杯(G1) NaN  18.0  4.0   8    3.5   2.0      5  北村友一  54.0  芝2200  良   **   2:14.4  0.3    **      5-6-6-5  37.6-34.6  33.3   448(-4)     NaN NaN      ラッキーライラック   1050.0
2016104750  2019/10/13   4京都4    晴  11.0             秋華賞(G1) NaN  17.0  3.0   5    6.9   4.0      1  北村友一  55.0  芝2000  稍   **   1:59.9 -0.3    **      6-7-5-5  34.6-36.4  36.1  452(+20)     NaN NaN    (カレンブーケドール)  10382.2
2016104750  2019/05/19  2東京10    晴  11.0            優駿牝馬(G1) NaN  18.0  1.0   2    4.1   2.0      3  北村友一  55.0  芝2400  良   **   2:23.2  0.4    **      4-4-4-5  35.1-35.3  35.4   432(-2)     NaN NaN      ラヴズオンリーユー   3164.4
2016104750  2019/04/07   2阪神6    晴  11.0             桜花賞(G1) NaN  18.0  2.0   4    5.7   3.0      3  北村友一  55.0  芝1600  良   **   1:33.1  0.4    **          8-9  35.4-33.3  32.9   434(-4)     NaN NaN       グランアレグリア   2954.7
2016104750  2019/02/11   1東京5    曇  11.0      デイリー杯クイーンC(G3) NaN   9.0  8.0   9    2.1   1.0      1  北村友一  55.0  芝1600  良   **   1:34.2  0.0    **          6-6  36.1-33.8  33.1   438(+2)     NaN NaN       (ビーチサンバ)   3532.9
2016104750  2018/12/09   5阪神4    晴  11.0       阪神ジュベナイルF(G1) NaN  18.0  5.0   9    3.6   2.0      2  北村友一  54.0  芝1600  良   **   1:34.2  0.1    **        17-17  34.8-35.0  33.9    436(0)     NaN NaN      ダノンファンタジー   2636.8
2016104750  2018/10/20   4東京6    晴   9.0           アイビーS(OP) NaN  10.0  1.0   1    6.5   3.0      1  北村友一  54.0  芝1800  良   **   1:48.6 -0.3    **        4-3-4  37.2-33.4  32.5   436(-4)     NaN NaN    (コスモカレンドゥラ)   1622.4
2016104750  2018/09/02  2小倉12    晴   5.0                2歳新馬 NaN  16.0  1.0   2    2.3   1.0      1  北村友一  54.0  芝1800  稍   **   1:50.0 -0.3    **      4-4-4-4  37.5-34.8  34.5    440(0)     NaN NaN      (マルカノーベル)    700.0

これをほかの馬でも同様に行っていきます。

#データ分析
15年分のレース結果と、掲示板内の馬のデータがそろったところで、ここからが本番です。

枠番、オッズ、前走までの成績をトータルして分析していきます。
pickleファイルは、pandasを用いて

read.py
import pandas as pd

pd.read_pickle('sample.pickle')

で読み込むことができます。
その後に様々な統計的手法を取ることができます。

##枠番
2020年から2006年までのもののデータをとると、

1枠[2 - 3 - 1 - 1]
2枠[2 - 2 - 1 - 5]
3枠[3 - 2 - 1 - 4]
4枠[2 - 3 - 3 - 4]
5枠[2 - 2 - 3 - 2]
6枠[2 - 1 - 2 - 5]
7枠[1 - 1 - 3 - 5]
8枠[1 - 1 - 1 - 4]
[1着-2着-3着-以下]

となっており、外枠が不利、中枠がやや有利の傾向が見えます。

##単勝オッズ
同様に、

  • 1倍台
    • [3 - 1 - 0 - 0]
  • 2倍台
    • [4 - 2 - 0 - 0]
  • 3倍台
    • [0 - 1 - 2 - 0]
  • 4~9倍台
    • [6 - 2 - 4 - 12]
    • ( 単勝8倍で[4-0-1-2]、5倍が最低 )
  • 10倍~
    • [2 - 3 - 3 - 4]
  • 20倍~ 
    • [0 - 1 - 1 - 8]
  • 30倍~ 
    • [0 - 3 - 3 - 3]
  • 50倍~ 
    • [0 - 2 - 1 - 3]
  • 100倍~
    • [0 - 0 - 0 - 1]

となっており、1着が単勝オッズ1, 2, 8倍台がの傾向が高いです。

##前走までの成績

  • G1

    • ジャパンカップ
      • [4 - 5 - 7 - 14]
    • 菊花賞
      • [4 - 2 - 2 - 2]
    • 天皇賞・秋
      • [4 - 2 - 2 - 1]
    • エリザベス女王杯
      • [0 - 4 - 0 - 4]
    • 宝塚記念
      • [1 - 0 - 0 - 2]
    • マイルチャンピオンシップ
      • [0 - 0 - 1 - 0]
    • 凱旋門賞
      • [1 - 0 - 1 - 2]
    • コックスプレート
      • [1 - 0 - 0 - 0]
    • メルボルンカップ
      • [0 - 1 - 0 - 0]
  • ほか

    • 金鯱賞(G2)
      • [0 - 2 - 0 - 1]
    • アルゼンチン共和国杯(G2)
      • [1 - 0 - 0 - 2]
    • 札幌記念(G2)
      • [0 - 0 - 1 - 1]
    • 朝日チャレンジカップ(G3)
      • [0 - 0 - 0 - 1]
    • 目黒記念(G2)
      • [0 - 1 - 0 - 0]
    • ステイヤーズステークス(G2)
      • [0 - 0 - 0 - 1]
    • 中日新聞杯(G3)
      • [0 - 0 - 1 - 0]
    • 産経大阪杯(G2)
      • [1 - 0 - 0 - 0]
    • 福島記念(G3)
      • [0 - 0 - 0 - 1]

といった成績となっています。

###まとめ

  • ジャパンカップ、菊花賞、天皇賞秋、エリザベス女王杯に出走している
  • 外枠でない

簡単にまとめると、掲示板に入る馬が、以上の2点を満たしている可能性が高いことがわかりました。

#予想
さて、以上を踏まえて僕のねらい目として

馬番 馬名 騎手
5 ディープボンド 和田竜二
7 クロノジェネシス C.ルメール
9 ステラヴェローチェ M.デムーロ
10 エフフォーリア 横山武史
11 アリストテレス 武豊
16 タイトルホルダー 横山和生

の6頭を挙げたいと思います。

買い方は

3連単フォーメーション
10
→7, 16
→5, 7, 9, 11, 16
計6点 × 100円

で賭けようと思っていたのですが、生涯収支マイナス一億円君がエフフォーリアを本命にしていたので、タイトルホルダーを本命にし、候補としてステラヴェローチェを追加して、

16
→7, 10
→5, 7, 9, 10

の 8点 × 100円 で勝負したいと思います!

#最後に

今回の目標であった、データの収集を簡単にする、という点ではスクレイピングは非常に有効だなと思いました。
データ分析に関しては今回は手動で行いましたが、これも機械学習を用いて自動化できるようにしていきたいです。

コントレイル、グランアレグリア、クロノジェネシスといった現役トップクラスを争ってきた馬が今年引退したので来年からはどの馬が台頭してくるのかが非常に見ものですね。
某ウイルスも落ち着いてきていますし、来年は競馬場に現地観戦しに行きたいです!

その戦いに、人は夢を見る。
「さぁ、夢を見よう。」

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?