AI競馬で回収率100%越えを目指して

はなむけ競馬場

python プログラム 競馬

[AI競馬]2歳未勝利戦の探索的データ解析(EDA) - 1

投稿日:

Kaggleで学んだことを、競馬解析に適用する。

一番最初に探索的データ解析をする。

ゴールタイムの正規性を確認

モデルの目的変数を修正タイム(ゴール時のタイム)と設定している。

目的変数は正規性があるほうが望ましいということで、正規分布している稼働確認する。


# Plots
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import skew, norm
import numpy as np

sns.set_style("white")
sns.set_color_codes(palette='deep')
f, ax = plt.subplots(figsize=(8, 7))
#Check the new distribution 
sns.distplot(train['修正タイム'], color="b",fit=norm);
ax.xaxis.grid(False)
ax.set(ylabel="Frequency")
ax.set(xlabel="修正タイム")
ax.set(title="修正タイム")
sns.despine(trim=True, left=True)
plt.show()

from scipy import stats

#正規確率プロット
fig = plt.figure()
res = stats.probplot(train['修正タイム'],plot=plt)
plt.show()

どうみても正規分布していない。

また、ゴールタイムの分布も何個かのグループに分かれている。

これはレースごとの距離に左右されるものなので、どうしてもそれに応じた適正なゴールタイムが出てくる。

タイムを予想するという設定のモデルで、全ての種類のレースを含めてしまうとどうしても正規分布ができそうにない。

距離ごとのレースタイムを確認する

まずはどれだけの種類のレースがあり、データ数がどうなっているのか確認する


#距離ごとのデータ数
train.groupby("距離").count()

ID 着順
距離
1000 988
1150 562
1200 10017
1300 410
1400 7488
1500 362
1600 6692
1700 716
1800 10028
2000 3459

 

レース距離に関しては2歳未勝利戦では10種類ある。

その中では1200M、1800Mが最も多い。

今後は距離別のモデルをそれぞれ作成していくことになる。

それぞれの分布を確認する。

元の分布に比べれば非常にきれいに分かれている。

距離に応じてモデルを作成していくことになる。

ヒートマップでタイムに影響するものを調べる


import seaborn as sns
import numpy as np

k = 10

corr = train_2012.corr()

cols = corr.nlargest(k,"修正タイム")["修正タイム"].index

cm = np.corrcoef(train_2012[cols].values.T)

sns.set(font_scale=1)

hm = sns.heatmap(cm,cbar=True,annot=True,square=True,fmt=".2f",annot_kws={"size":5},yticklabels=cols.values,xticklabels=cols.values)

plt.show()

 

着順は未来のデータになるので、除外する。

それ以外のデータを見ると、もはやタイムと密接に関連する因子は手元に存在しない。

最大でも相関係数が0.2というのは、あまりにも低すぎる。

単独の特徴量だけだと、予測するのは厳しそうなので、今後の特徴量エンジニアリングが結果を大きく左右すると思う。

3着以内とそれ以外でのタイムの差を見る

 


sns.set_style("white")
sns.set_color_codes(palette='deep')
f, ax = plt.subplots(figsize=(4, 4))
#Check the new distribution

sns.distplot(train_2012[(train_2012["距離"] == 1200) & (train_2012["着順"] < 4)]["修正タイム"], color="g");

(mu, sigma) = norm.fit(train_2012[(train_2012["距離"] == 1200) & (train_2012["着順"] > 3)]["修正タイム"])
print("3着以内")
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))

plt.legend(['3着以内 緑. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
loc='best')

sns.distplot(train_2012[(train_2012["距離"] == 1200) &(train_2012["着順"] > 3)]["修正タイム"], color="b");
(mu, sigma) = norm.fit(train_2012[(train_2012["距離"] == 1200) & (train_2012["着順"] >;3)]["修正タイム"])
plt.legend(['着外 青. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)])
print("着外")
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))

ax.xaxis.grid(False)
ax.set(ylabel="Frequency")
ax.set(xlabel="修正タイム")
ax.set(title="修正タイム -" + str(1200) + "M")
sns.despine(trim=True, left=True)
plt.show()

結果
3着以内

mu = 71.40 and sigma = 1.66

着外

mu = 72.99 and sigma = 2.13


結果的に3着以内に来る馬はだいたい72秒以下でゴールし、着外だと73秒近くかかることが分かった。
もちろん、標準偏差があるので、70秒でゴールしても着外ということもある。
レースなので当たり前だが、その他の馬の強さも結果に大きく作用する要素であることがうかがえる。

レース中の他の馬のデータも入れておかないと、モデルが他の馬のことも考慮することができない。
特徴量が多くなりすぎるのは嫌だが、こればかりは18頭の馬のデータが入るように列を追加する必要があるだろう。

 

馬番によってタイムやゴールする順番に影響があるか?

しもふりチューブの競艇の回で、内側ほど有利という話があったので、競馬ではどうなのかということを確認の意味を込めて可視化する。

【タイム】

【着順】

どちらをみても、右肩上がり、下がりにもなっていないので、特段位置による有利・不利はないように見受けられる。

競馬について調べている間に、そういった話を聞いた覚えがないので、そういうことなのだろう。

 

まとめ

  • 距離ごとのモデルを作成する
  • タイムに直結する特徴量は今のところ持っていない
  • 3着以内の馬は71秒前後でゴールする。それ以外は73秒程度。(1200M)
    • わずか二秒の差であるので、0.1秒単位がかなり重要になる
  • 競艇と異なり、出走位置による有利・不利は見受けられない

-python, プログラム, 競馬

Copyright© はなむけ競馬場 , 2021 All Rights Reserved Powered by AFFINGER5.