はじめに
前回の記事で収集したデータを基に、1位になる馬の番号を予想させる。
上記記事にも書いたが、馬柱が記録され始めたのが2007年の後半からなので、今回の挑戦では2008年以降のデータのみ使用する。
要約
最終的な精度は、学習用データで35%程度、テスト用データでは20%程度と結構低い。
学習時には過学習の傾向も見られたので、色々と見直しが必要かも。
過学習の要因を考えると、馬柱が埋まっていないレースが多いことが原因の可能性があるので、その辺を考慮した学習データに整理して再び検証してみる予定。
今回のアプローチ
とりあえずディープラーニング使って1位を予想させればええやろガハハ
以下の2つを試した。
- DNNで予想
- CNNで予想
まずは、入力データを単純に一直線に並べてDNNに入力して精度を評価してみる。
その後、入力データそのまま(2次元構造)をCNNに入力して精度を評価する。
1.DNNで予想
DNNの構造は以下のプログラム。
損失関数はCategoricalCrossentropy
。
最適化関数はAdam(learning_rate=0.0001, beta_1=0.5, beta_2=0.999)
。
def CreateModel():
inputs = Input(shape=(18 * 9,))
dense = Dense(512, activation="relu")(inputs)
dense = Dense(256, activation="relu")(dense)
dense = Dense(128, activation="relu")(dense)
dense = Dense(64, activation="relu")(dense)
outputs = Dense(18, activation="softmax")(dense)
return inputs, outputs
これで学習させた結果が以下のグラフ。
とても分かりやすく過学習してる。
今回のデータの入力形式は、単純に一直線に並べただけなので、その影響もあるかもしれない。
2.CNNで予想
kerasでは何故かCNNが動かなかったのでpytorchに変えて実験。
CNNの構造は以下のプログラム。
損失関数はnn.CrossEntropyLoss
。
最適化関数はAdam(model.parameters(), lr=0.001, betas=(0.5, 0.999))
。
def __init__(self):
super(Model2d, self).__init__()
bias = True
self.input = nn.Sequential(
nn.Conv2d(in_channels=1,
out_channels=32,
kernel_size=(1, 1),
padding=(0, 0),
stride=(1, 1),
bias=bias),
nn.ReLU(),
)
self.hidden = nn.Sequential(
nn.Conv2d(in_channels=32,
out_channels=32,
kernel_size=(3, 3),
padding=(1, 1),
stride=(1, 1),
bias=bias),
nn.Dropout(0.2),
nn.ReLU(),
nn.Conv2d(in_channels=32,
out_channels=64,
kernel_size=(3, 3),
padding=(1, 1),
stride=(1, 1),
bias=bias),
nn.Dropout(0.2),
nn.ReLU(),
nn.Conv2d(in_channels=64,
out_channels=64,
kernel_size=(3, 3),
padding=(1, 1),
stride=(1, 1),
bias=bias),
nn.Dropout(0.2),
nn.ReLU(),
)
self.output = nn.Sequential(
nn.Conv2d(in_channels=64,
out_channels=1,
kernel_size=(1, 1),
padding=(0, 0),
stride=(1, 1),
bias=bias),
nn.Flatten(),
nn.Linear(18 * 9, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 18),
)
def forward(self, x):
input = self.input(x)
middle = self.hidden(input)
output = self.output(middle)
return output
これで学習させた結果が以下の2つのグラフ。
過学習の気配があるので60epoch程度で中断した。
CNNを使う場合でも、やはり学習時はlossが下がり続け、accが上がり続ける結果となった。
傾向はDNNと似たような感じである。
学習時のlossは順調に下り続けるが、テスト時は、最初は減少傾向で途中から上がり始める。
accは、学習時は順調に上がり続け、テスト時は早々に頭打ちになる。
めちゃくちゃ過学習してそう。
要因分析
現時点での仮説は以下のとおり。
- 勝つ馬の番号が偏っている
- 馬柱がちゃんと埋まっているデータが2割くらいしか無い
勝つ馬の番号が偏っている
2008年~2022年の中央競馬で、1位になった馬の番号を集計したのが以下の棒グラフ。
左から順に1番、2番、……、18番。
縦軸はレース数。
割合にしたのが以下の表。
馬番 | 勝率(%) |
---|---|
1 | 7 |
2 | 7 |
3 | 7 |
4 | 8 |
5 | 7 |
6 | 7 |
7 | 7 |
8 | 7 |
9 | 7 |
10 | 7 |
11 | 6 |
12 | 6 |
13 | 5 |
14 | 4 |
15 | 3 |
16 | 3 |
17 | 0 |
18 | 0 |
という感じで、ある馬番に偏ってるわけではなさそう。(すごい)
なお、後ろの番号ほど割合が減っているのは、単純に少ない頭立てのレースが多いから。
頭立て数の影響もあるだろうが、こんだけ綺麗に分布してるなら影響力は弱い気がする。
よって、「勝つ馬の番号が偏っている」という仮説は否定された。
馬柱が埋まっているデータが2割程度
2008年~2022年のデータのレース数は51808。
そのうち、馬柱が5枠全て埋まっていたレースは11615。
割合としては約22.4%となる。
2023年に開催されたレース数は3400。
そのうち、馬柱が5枠全て埋まっていたレースは707。
割合としては約20.8%。
よって、この仮説は正しそう。
馬柱がちゃんと埋まっているレースであれば高い割合で予想できる可能性がある。
結論
2008年~2022年の中央競馬の全レースのデータを使った場合、予想精度がかなり低く、過学習してそうな気配があった。
その要因を分析したところ、馬柱のデータがちゃんと埋まっているレースについては正しく予想できている可能性が浮上した。
今後はそのデータだけを使って分析できるか試す予定。