競走馬をレーティングしてみた(Glicko2 Rating System)
競走馬の強さを評価するために競走馬のレーティングをしてみました。レーティングはGlicko2 Rating Systemというのを使用してみました。Glicko2の概要やPythonでの実装方法については以下の記事にまとめたので、良ければ見てください。
book-read-yoshi.hatenablog.com
レーティングは2015年以降のレース結果を基に実施しました。結果は以下の通りです。上位10頭まで表示してます。感覚と一致しますか??
レーティング用に作成したPythonコードは以下の通りです。レースデータの取得はこちらを参考にしました。以下ではレースデータの取得方法は割愛してます。
from glicko2 import glicko2 import pickle import pandas as pd pd.set_option('display.max_columns', 100) import numpy as np from tqdm.notebook import tqdm as tqdm # レーティングを行う関数 def calcRatings(players,ranks): newPlayers=[] for i, (target_player,target_rank) in enumerate(zip(players,ranks)): new_target_player = copy.deepcopy(target_player) ratings=[] rds=[] outcomes=[] for j, (player, rank) in enumerate(zip(players,ranks)): if not i==j: ratings.append(player.rating) rds.append(player.rd) if rank>target_rank: outcomes.append(1) elif rank<target_rank: outcomes.append(0) elif rank==target_rank: outcomes.append(0.5) new_target_player.update_player(ratings, rds, outcomes) newPlayers.append(new_target_player) return newPlayers # 事前に取得した競馬レースデータをロードする。競馬データの取得は以下を参考にした。 # http://houdoukyokucho.com/2020/08/31/post-1617/ with open('df_with_race_data.pickle', 'rb') as f: df = pickle.load(f) # 中止レース等を除外 df = df[df["rank"]!="中止"] df = df[df["rank"]!="除外"] df = df[df["rank"]!="取消"] df = df[df["rank"]!="失格"] # レート等を格納する列を作成 df["horse_rate"]=np.nan df["horse_rd"]=np.nan df["horse_vol"]=np.nan # レーティング結果を格納するデータフレームを作成 def createRatingTable(df, colName): df = df[[colName]].copy() df = df.drop_duplicates() df["rating"] = 1500 df["rd"] = 350 df["vol"] = 0.06 return df df_horse_rate = createRatingTable(df, "horse_name") # レーティング処理を高速化するためにPandasをリストに変換 horse_rates = df_horse_rate.values.tolist() # 各競走馬の最新のレート情報等を登録するリスト race_datas = df.values.tolist() # レースデータを蓄積したリスト # レース単位に繰り返し計算を行う finished = [] for i,race_data in enumerate(tqdm(race_datas)): target_race_id = race_data[12] # [12]は列番号なのでデータによって異なる if target_race_id not in finished: finished.append(target_race_id) single_race = [race_data for race_datain race_datas if race_data[12]==target_race_id] ranks = [int(horse[15]) for horse in single_race] # [15]は列番号なのでデータによって異なる horse_names = [single_record[3] for single_record in single_race] # [3]は列番号なのでデータによって異なる # 将来的に機械学習等を行うときの説明変数とするために、レース前のレートを記録しておく horses = [] for j, horse_name in enumerate(horse_names): # 過去レートを取得 horse_rate,horse_rd,horse_vol = [horse_rate for horse_rate in horse_rates if horse_rate[0]==horse_name][0][1:4] player = glicko2.Player(horse_rate,horse_rd,horse_vol) horses.append(player) # レースデータのリストに登録 ※以下の[25:28]は列番号なので作成データによって異なる race_datas[i+j][25:28] = [horse_rate,horse_rd,horse_vol] # 競走馬のレートを計算する new_horses = calcRatings(horses, ranks) # 各競走馬の最新のレート情報を記録 for horse_name, new_horse in zip(horse_names,new_horses): for j,horse_rate in enumerate(horse_rates): if horse_rate[0] == horse_name: horse_rates[j][1:4]=[new_horse.rating, new_horse.rd, new_horse.vol] # レートを高い順に表示する df_rate = pd.DataFrame(horse_rates,columns=["horse_name","rating","rd","vol"]) df_rate.sort_values("rating",ascending=False)