いよいよ夏競馬が開幕した。
ところが、成績があまりに悪いので、夏を超すどころか破産危機も感じるので、これを回避するために機械学習を使ってみようと思う。
特に、新潟5レースのメイクデビュー新潟がなんとも酷い結果だったので、ここからまじめに分析しようと思う。
といっても、通常の競馬の振り返りとは異なり、単にデータ分析の手法を適用して馬券購入手法について、何か言えないか考察した結果を示す。
###やったこと
・単勝人気の読み方
・シミュレーションしてグラフにしてみる
・フラクタルということ
###・単勝人気の読み方
先日の新潟の予想や結果はJRAに掲載されている。直接リンクが難しいので以下から結果などで新潟7月28日日曜日5Rメイクデビュー新潟
メイクデビュー新潟
過去情報は以下からpdfで取得できます。
第2回 新潟競馬 第2日
まず、単勝・複勝人気は以下のとおりです。
競馬は、単勝というのは一番を当てる、複勝とは三番までに入るかを当てるゲームです。ほかに、一着ー二着や、一二三着を当てるというのもあります。
ということで、この示された人気が正しければ、想像のとおり1-3番人気の馬を買えば当たりそうな気がします。ちなみにこのオッズは一番に来た時の払い戻しの倍率です。すなわち、1.8倍だと100円が180円になって戻ってきます。
つまり、そのまま考えるとこの数字が一番になる確率の逆数だと考えていいと思います。
※実際には、払い戻し率がそれぞれ設定されていて、だいたい70-80%程度戻すことになっているので、2-3割減と考えればいいと思います。その割引を考慮したのが上記の1.8倍ですから、実際の確率は20%程度いいわけです。
ということで、この単勝の倍率が勝つ確率の逆数と考えて、以下のような計算をしてみました。
###・シミュレーションしてグラフにしてみる
コードは以下のとおりです。
まず、乱数で1-15の数字を重複無しで出力してみます。
つまり、どの馬も同じ確率で走った場合の順位です。
from numpy.random import *
from numpy import *
import csv
city = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
rand_=[]
rand_=random.choice(city,15,replace=False) # 5個をランダム抽出(重複なし)
print('randn()',rand_)
当然、ランダムに数字が並びます。
randn() [ 3 11 15 8 12 7 2 10 13 5 1 4 6 14 9]
次に、上記の単勝倍率を使って、重みづけしてみます。
この場合のコードは以下のとおりになります。
※もっとシンプルにかけそうですが。。
最初に確率を計算します。以下を参考にしています。
【参考】
Numpyによる乱数生成まとめ
# 確率を重み付けする場合
sum_=1/1.8+ 1/4+ 1/7.7+ 1/16.7+ 1/19.1+ 1/24.8+ 1/41.2+1/54.5+ 1/58.6+ 1/63.1+ 1/78.4+ 1/92.6+ 1/111+ 1/137.1+1/218
print(sum_)
weight = [1/1.8/sum_, 1/4/sum_, 1/7.7/sum_, 1/16.7/sum_, 1/19.1/sum_, 1/24.8/sum_, 1/41.2/sum_,1/54.5/sum_,1/58.6/sum_, 1/63.1/sum_, 1/78.4/sum_, 1/92.6/sum_, 1/111/sum_, 1/137.1/sum_,1/218/sum_]
CSV出力するために出力ファイルを定義しています。
※ここまとめて出力できるはずですが、今はエクセルに縦に並べています
また、それぞれ一着、二着、三着の数字が重複しないように工夫しています。
with open('./Keiba/keiba_perspective.csv', 'w', newline='') as f:
rand1_=[]
rand2_=[]
rand3_=[]
for i in range(100):
rand_1=random.choice(city, p=weight) # 指定した確率で1個を抽出
rand_2=random.choice(city, p=weight)
while rand_2==rand_1:
rand_2=random.choice(city, p=weight)
rand_3=random.choice(city, p=weight)
while rand_3==rand_1 or rand_3==rand_2:
rand_3=random.choice(city, p=weight)
print(i,'rand_',rand_1,rand_2,rand_3)
rand1_.append(rand_1)
rand2_.append(rand_2)
rand3_.append(rand_3)
writer = csv.writer(f)
writer.writerow(map(lambda x: x, rand1_))
writer.writerow(map(lambda x: x, rand2_))
writer.writerow(map(lambda x: x, rand3_))
この結果、おまけのように出力されます。
予想に反して、1や2が少ない、9-7-1や10-3-4などめったに出そうにないのが割と多く出現しています。
これを表にしてみると、以下のようなものが得られます。
グラフにしてみると。。以下のようになります。
そして、確率が小さい領域をみるためにlog-logプロットしてみると、
上記から、単勝の確率が1割に満たなくとも、100回に10回位も3着までに顔を出していることが分かります。
そして、1%程度の馬(12以下の4頭合わせて)10回位顔を出すんですね。
※これが大穴狙いが成立する理由だったのかもしれません
###・フラクタルということ
ここが本当は一番書きたかったところです。
つまり上記のままだと馬券は大穴狙いという結論になりかねません。
※正しいかもしれませんが、。。。
というわけで、もう少しそのレースを特徴づけるパラメータが無いか探してみます。
通常の人気と倍率は以下のようになっています。
これを通常よくやるように両軸の対数を取ってみます。
すごくというほどではありませんが、一定の法則性がありそうです。
つまり、通常のフラクタル現象でみるようなべき乗則が成り立っているようです。
そしてこれを個別のレースについてみると以下のようになっています。
上から、新潟5R、札幌5R、6R、12R、11R、10R、9Rの縦軸人気順位、横軸倍率をしめしています。
そして、結果と人気との相関係数は以下のようになっています。
- | N5R | 5R | 6R | 12R | 11R | 10R | 9R |
---|---|---|---|---|---|---|---|
相関係数 | 0.33 | 0.45 | 0.53 | 0.58 | 0.59 | 0.28 | 0.51 |
単勝 | 2480 | 180 | 200 | 1580 | 230 | 840 | 180 |
3連複 | 43210 | 1540 | 610 | 46370 | 12310 | 3500 | 5530 |
人気順位 | 6-3-8 | 1-3-6 | 1-2-3 | 5-4-8 | 1-5-9 | 4-7-1 | 1-5-9 |
結果として単勝が転んでいるのが、N5R,12R,10R辺りでこれはグラフ見ると一番人気と二番手以下との差が極めて小さいという特徴があります。そして、3連複は同じくN5R,12Rそして11R辺りが高い配当になっています。こちらも2-8番人気が塊になっていて、どれが来てもおかしくない状況と言えます。 | |||||||
実際に、それぞれ人気順位でいうと最下段にようになっています。11Rと9Rは全く同じ1-5-9でした。そしてグラフも心なしか似ています。さらに、5R,6Rもほぼ本命で1着固定で二から六まで二着グループでその通りの結果なので、本命と呼べるでしょう。一方、6Rは大本命でグラフも1-4着まで安定の人気でそのままの着順になりました。 | |||||||
最後に、大番狂わせのN5Rと12Rですが、グラフは綺麗に直線的でN5Rは相関係数小さくでたらめな結果です。一方、12Rは相関係数はそれほどでたらめではありませんが、一番人気不在で後ろの集団との人気差が小さいことがわかります。どちらも一番人気あたりのグラフが上に凸で、こういうのは一番人気不在だと見えます。また、後ろの集団との差が小さいグラフも大番狂わせの予兆だと言えると思います。 | |||||||
###まとめ | |||||||
・競馬の人気と結果についてデータ分析してみた | |||||||
・確率に基づくシミュレーションを実施して予想よりも人気下位の馬が1-3位に入ることを見た | |||||||
・人気と結果の相関、および人気順位と倍率のグラフからそのレースが荒れるかどうかの判断指針を見出すことができた | |||||||
①一番人気近傍の上に凸は荒れる | |||||||
②人気第二集団との距離が近いと荒れる |
さらに、データ分析を重ねて競馬の法則を確立したいと思う。
###おまけ
0 rand_ 1 9 2
1 rand_ 4 2 1
2 rand_ 9 7 1
3 rand_ 10 3 4
4 rand_ 4 1 2
5 rand_ 1 2 5
6 rand_ 2 4 6
7 rand_ 3 4 2
8 rand_ 7 1 14
9 rand_ 2 1 7
10 rand_ 1 8 4
11 rand_ 6 1 2
12 rand_ 1 3 2
13 rand_ 2 1 4
14 rand_ 1 2 9
15 rand_ 4 1 6
16 rand_ 5 1 6
17 rand_ 1 5 2
18 rand_ 3 4 2
19 rand_ 1 12 2
20 rand_ 3 1 2
21 rand_ 1 3 2
22 rand_ 1 7 5
23 rand_ 1 15 2
24 rand_ 1 5 3
25 rand_ 1 4 8
26 rand_ 5 4 2
27 rand_ 1 2 6
28 rand_ 3 1 2
29 rand_ 4 1 2
30 rand_ 3 9 1
31 rand_ 2 7 3
32 rand_ 1 3 2
33 rand_ 1 3 7
34 rand_ 2 1 3
35 rand_ 1 3 12
36 rand_ 1 2 3
37 rand_ 1 6 3
38 rand_ 2 1 10
39 rand_ 4 2 1
40 rand_ 1 4 9
41 rand_ 2 1 4
42 rand_ 3 4 7
43 rand_ 1 2 3
44 rand_ 1 2 9
45 rand_ 7 2 1
46 rand_ 1 2 3
47 rand_ 4 1 3
48 rand_ 1 2 6
49 rand_ 8 1 5
50 rand_ 11 9 8
51 rand_ 1 4 3
52 rand_ 11 6 2
53 rand_ 2 11 1
54 rand_ 3 1 2
55 rand_ 1 2 15
56 rand_ 2 1 4
57 rand_ 1 6 2
58 rand_ 2 1 13
59 rand_ 2 1 10
60 rand_ 2 6 1
61 rand_ 1 6 12
62 rand_ 1 3 8
63 rand_ 1 3 4
64 rand_ 1 2 6
65 rand_ 2 1 7
66 rand_ 3 5 2
67 rand_ 1 2 10
68 rand_ 6 3 1
69 rand_ 1 2 3
70 rand_ 1 5 13
71 rand_ 1 2 9
72 rand_ 2 1 6
73 rand_ 1 2 3
74 rand_ 2 1 4
75 rand_ 1 4 11
76 rand_ 1 6 2
77 rand_ 1 3 10
78 rand_ 11 4 1
79 rand_ 10 1 3
80 rand_ 4 1 3
81 rand_ 2 1 4
82 rand_ 1 2 4
83 rand_ 3 1 10
84 rand_ 1 6 3
85 rand_ 2 7 1
86 rand_ 15 3 2
87 rand_ 1 2 6
88 rand_ 9 2 1
89 rand_ 4 2 1
90 rand_ 3 1 5
91 rand_ 1 2 14
92 rand_ 1 2 3
93 rand_ 2 3 1
94 rand_ 2 5 1
95 rand_ 1 3 2
96 rand_ 3 11 9
97 rand_ 1 2 3
98 rand_ 1 5 9
99 rand_ 1 2 4