【競馬】いちばん強いのはどの子?~TrueSkillによる競走馬レーティング~


競走馬、どの子がいちばん強いんでしょうね。
荒れそうな話題です。コンピュータに数字で解決してもらいましょう(さらに荒れそう)

まえがき

競走馬のレーティング

正式なレーティングとしては国際的な基準に基づくロンジンワールドベストレースホースランキングがあります。2023年6月現在、イクイノックスが世界一のレーティングをたたき出していることも話題になりました。

しかしながら国際的なものでもあるため、例えばJRAの午前の3歳未勝利レースなどは算定の対象にはならないようです。

それはそう

TrueSkillについて

さて、ここにMicrosoftさんが開発したTrueSkillなるアルゴリズムがあります。複数人対戦に対応したレーティングアルゴリズムで、XBoxのゲームでのマッチング等に使われているようです。複数人対戦に対応してるというのは競馬にはうってつけです。技術的詳細は下記に詳しいですが、正直わからん

わからないんですが、Python実装があるのでそちらを使います。

幸いというかなんというか、元データとして手元には競馬予想AIをつくろうと収集した2015年からのレース結果データがあります。

これらを使用して、近年の競馬でどの競走馬が「いちばん強かったか」を算出してみようと思います。

先行事例

この話はわたくしが思いついたわけではなく、下記の先行事例を大いに参考にさせてもらいました。というかソースはほぼそのままです。

すみません(ありがとうございます)

やってみよう

Pythonによる実装

今回用いるデータは、2015年1月より2023年6月までのJRA全レースの結果より抽出した下記のようなものです(RaceID、着順、日付によりソートされています)

RaceID 着順 HorseID 馬名 Date
0 201506010101 1 2012105911 カイマノア 2015-01-04
1 201506010101 2 2012103557 ゴールドエッグ 2015-01-04
2 201506010101 3 2012101349 ジュエルアラモード 2015-01-04
3 201506010101 4 2012100085 ファインダッシュ 2015-01-04
4 201506010101 5 2012100821 ハルダヨリ 2015-01-04
413144 202309030812 12 2019105860 オースミメッシーナ 2023-06-25
413145 202309030812 13 2018100985 ペプチドサンライズ 2023-06-25
413146 202309030812 14 2019102491 プレイテシア 2023-06-25
413147 202309030812 15 2017106270 ナムラボス 2023-06-25
413148 202309030812 16 2018110017 スカイナイル 2023-06-25

 

このデータを使って、実際にTrueSkillによりレーティングを算出してみます。

(上記のデータはデータフレームとしてdf_ratingに格納されているものとします)

import pandas as pd
import numpy as np
import trueskill

mu = 25.
sigma = mu / 3.
beta = sigma / 2.
tau = sigma / 100.
draw_probability = 0.001
backend = None
env = trueskill.TrueSkill(
   mu=mu, sigma=sigma, beta=beta, tau=tau,
   draw_probability=draw_probability, backend=backend)

race_list = list(df_rating.loc[:,'RaceID'].unique())
horse_list = list(df_rating.loc[:,'HorseID'].unique())

rate_dict = {k:env.create_rating() for k in horse_list}
rate_dict = {k:(v,v) for k,v in rate_dict.items()}

rate_before_ = []
race_after_ = []
for race in race_list:
    df_race = df_rating[df_rating.loc[:,'RaceID'] == race]
    rate_before = [env.expose(rate_dict[el[2]][0]) for el in list(df_race.values)]
    teams = [(rate_dict[el[2]][0],) for el in list(df_race.values)]
    teams = env.rate(teams, ranks=list(range(len(df_race))))
    rate_after = [env.expose(t[0]) for t in teams]
    for i, el in enumerate(list(df_race.values)):
        rate_dict[el[2]] = (teams[i][0], max(rate_dict[el[2]][0], teams[i][0]))
    rate_before_ += rate_before
    race_after_ += rate_after

df_rating.loc[:,'レース前レート'] = rate_before_
df_rating.loc[:,'レース後レート'] = race_after_

display(df_rating)

 

実行結果

RaceID 着順 HorseID 馬名 Date レース前レート レース後レート
0 201506010101 1 2012105911 カイマノア 2015-01-04 0.000000 21.718523
1 201506010101 2 2012103557 ゴールドエッグ 2015-01-04 0.000000 20.050202
2 201506010101 3 2012101349 ジュエルアラモード 2015-01-04 0.000000 18.514712
3 201506010101 4 2012100085 ファインダッシュ 2015-01-04 0.000000 17.151930
4 201506010101 5 2012100821 ハルダヨリ 2015-01-04 0.000000 15.902128
413144 202309030812 12 2019105860 オースミメッシーナ 2023-06-25 24.594729 24.837411
413145 202309030812 13 2018100985 ペプチドサンライズ 2023-06-25 29.581136 29.195539
413146 202309030812 14 2019102491 プレイテシア 2023-06-25 21.248483 21.602119
413147 202309030812 15 2017106270 ナムラボス 2023-06-25 27.285971 27.085189
413148 202309030812 16 2018110017 スカイナイル 2023-06-25 24.956057 24.551795

よさそうな感じです

いちばん「強かった」のは?

表示の簡単のため、HorseID、馬名、Date、レース後レートのみの表示とします。

df_rating=df_rating[['HorseID','馬名','Date','レース後レート']]

(2015以降)ベスト20

上記にて算出したレーティング値を(各馬のキャリアハイとなる)値の高い順に並べてみます(ベスト20を表示)

df_rating.sort_values('レース後レート', ascending=False).drop_duplicates(subset='HorseID').head(20)

結果は下記の通り。なお、Dateはそのレーティング値をたたき出したレースの開催日となります。

HorseID 馬名 Date レース後レート
289661 2015104961 アーモンドアイ 2020-11-29 47.109769
337254 2017101835 コントレイル 2021-11-28 46.878123
336721 2016104532 グランアレグリア 2021-11-21 46.512941
340968 2018105027 エフフォーリア 2021-12-26 45.891798
340970 2016104750 クロノジェネシス 2021-12-26 45.717448
413116 2019105219 イクイノックス 2023-06-25 44.538779
110732 2013106101 サトノダイヤモンド 2017-03-19 44.171657
255900 2016104505 サートゥルナーリア 2020-03-15 44.016735
304002 2017100720 デアリングタクト 2021-03-14 43.920770
410003 2019104462 セリフォス 2023-06-04 43.912850
258720 2016102179 ダノンキングリー 2020-04-05 43.900767
293513 2015105046 ラッキーライラック 2020-12-27 43.865839
293512 2015105075 フィエールマン 2020-12-27 43.841517
329725 2017105563 レシステンシア 2021-10-03 43.822326
362472 2018110007 シュネルマイスター 2022-06-05 43.801520
197275 2014106201 レイデオロ 2018-12-23 43.742313
336724 2015104688 インディチャンプ 2021-11-21 43.705738
213411 2015102367 ダノンプレミアム 2019-04-21 43.585643
244837 2014106220 リスグラシュー 2019-12-22 43.571278
86645 2013105906 シンハライト 2016-09-18 43.092663

おお、これは……

というわけで、最もレーティング値が高かったのはアーモンドアイ(2020年ジャパンカップ勝利後)でした!

おお、納得。以下数々の名馬が続きます。わりと実感に沿った順位となってますね。TrueSkillの実力とレーティングの妥当性を感じます。

先日宝塚記念を勝ったイクイノックスは現状6位となりました。これから値を伸ばしていくでしょう。

全体に、JRAのレースにコンスタントに出走し、好走を続けた馬を高く評価するようです(海外成績は考慮していないのでそれはそうですね)。

2023クラシック世代ベスト20

同様に、2023年のクラシックを盛り上げた世代(2020年生まれ)で同様の順位付けを実施してみます。2023クラシック世代は2020年生まれなので、HorseIDが2020から始まることを利用します。

df_rating2020=df_rating.query("HorseID.str.startswith('2020')")
df_rating2020.sort_values('レース後レート', ascending=False).drop_duplicates(subset='HorseID').head(20)

結果は……

HorseID 馬名 Date レース後レート
408620 2020103656 リバティアイランド 2023-05-21 42.205391
409332 2020103532 タスティエーラ 2023-05-28 39.494939
409333 2020102899 ソールオリエンス 2023-05-28 39.285717
408621 2020103458 ハーパー 2023-05-21 38.674583
408626 2020103368 コナコースト 2023-05-21 38.373944
409339 2020106582 ファントムシーフ 2023-05-28 37.956769
406603 2020104243 オオバンブルマイ 2023-05-07 37.590486
408628 2020103732 ドゥアイズ 2023-05-21 37.449103
409146 2020102764 モズメイメイ 2023-05-27 37.365129
409335 2020102781 ベラジオオペラ 2023-05-28 36.933963
408624 2020101608 シンリョクカ 2023-05-21 36.845168
411980 2020101874 ペリエール 2023-06-18 36.700559
387760 2020101533 ドルチェモア 2022-12-18 36.568839
410015 2020103075 シャンパンカラー 2023-06-04 36.389293
402712 2020103364 ペリファーニア 2023-04-09 36.313704
409148 2020100896 ビッグシーザー 2023-05-27 35.408171
406606 2020103322 モリアーナ 2023-05-07 35.331011
410830 2020103589 ブトンドール 2023-06-11 35.253020
409334 2020105681 ハーツコンチェルト 2023-05-28 35.243370
408623 2020103390 ラヴェル 2023-05-21 35.199534

リバティアイランド強すぎ!!!

もしリバティアイランドがダービーに出ていたらどうなったんでしょうね。妄想が広がります。

まとめ

Microsoftによるレーティングアルゴリズム、TrueSkillを用いて2015年以降のJRA開催レース結果より、競走馬のレーティングを実施してみました。おおむね実感に沿う結果となって満足です。

TrueSkill、すごいですね