#はじめに
この記事は、SLP KBIT AdventCalendar2021 23日目の記事です。
今年某コンテンツのおかげで競馬にハマり、高松宮記念から競馬を見始めたのですが、好きになった馬が続々と引退していってしまい少し悲しいです。12/26(日)に行われる有馬記念でも引退を表明した名馬が2頭います。 キセキ と クロノジェネシス です。キセキは2017年の菊花賞以降勝利がないですが、重賞でも十分馬券圏内に入っており、引退レースでも是非とも馬券に絡んでほしいですね。現役最強との呼び声高いクロノジェネシスは今年凱旋門賞にも出走しました。前人未到のグランプリ4連覇に期待がかかります。
そして、女王クロノジェネシスに挑む有力馬が、 エフフォーリア 、 タイトルホルダー 、 ステラヴェローチェ 、 アリストテレス 、 アカイイト です。中でも、エフフォーリアはコントレイルやグランアレグリアといった古馬の中でもトップクラスの実力を持つ2頭を相手に天皇賞・秋で完勝しています。
今年を締めくくるのにふさわしい顔ぶれとなったグランプリ有馬記念ですが、我々にとっては予想を立てる上でデータの収集が必要となってきます。そんなデータの収集をPythonを用いて便利にできないか、というのがこの記事の内容です。
#まず何をするのか?
まずは去年までのデータを集めないことには話になりません。
2020~2006年までの15年間の有馬記念のレース結果をpandasとBeautifulSoupを用いてスクレイピングしていきます。
netkeiba様からスクレイピングを行っていきます。
コードは下のようになります。
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年の物をスクレイピングした結果はこのようになります。
着順 枠番 馬番 馬名 性齢 斤量 騎手 タイム 着差 単勝 人気 馬体重 調教師 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頭の特徴を調べるべく、前走までのデータを収集していきます。
コードは以下のようになります。
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年有馬記念勝ち馬のクロノジェネシスでの出力は以下のようになります。
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を用いて
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]
- 金鯱賞(G2)
といった成績となっています。
###まとめ
- ジャパンカップ、菊花賞、天皇賞秋、エリザベス女王杯に出走している
- 外枠でない
簡単にまとめると、掲示板に入る馬が、以上の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円 で勝負したいと思います!
#最後に
今回の目標であった、データの収集を簡単にする、という点ではスクレイピングは非常に有効だなと思いました。
データ分析に関しては今回は手動で行いましたが、これも機械学習を用いて自動化できるようにしていきたいです。
コントレイル、グランアレグリア、クロノジェネシスといった現役トップクラスを争ってきた馬が今年引退したので来年からはどの馬が台頭してくるのかが非常に見ものですね。
某ウイルスも落ち着いてきていますし、来年は競馬場に現地観戦しに行きたいです!
その戦いに、人は夢を見る。
「さぁ、夢を見よう。」