やりたい放題

好き勝手やってます。関西弁で書きます。

Pythonで足し算馬券の発生確率を解いてみた②

よう、ワイやで。今回は前回の続きやね。
関西弁で書くって言うてもたから、関西弁で書くわ。 Pythonを使って、馬券に絡んだ馬番が足し算になる足し算馬券の確率を求めるんよ。

Pythonの練習用なので、競馬を知らない人もちょっと気軽に寄っていってや。
目的がはっきりしてないと練習なんか身につかへんからね。
具体的に何ができる、とか、何に使えるってのは大事やで。

前回の話はこちら。

demrum.hatenablog.com

その結論はこちら。やけど、これは競馬ブログやから、興味ない人は見んでもええで。

keiba-talk.com

やること

  1. 各出走頭数のレースの馬番の組み合わせを全部求める

  2. 各出走頭数のレースの足し算になる馬番の組み合わせを全部求める

  3. 「1.」と「2.」より足し算の発生する理論値(確率)を求める

  4. 実際の過去の成績から、各出走頭数のレース数を求める

  5. 実際の過去の成績から、各出走頭数の足し算馬券の発生数を求める

  6. 「4.」と「5.」より足し算の発生した実績値を求める

  7. 「3.」と「6.」の比較を行う

前回は、1~3まで終わっているので、今日は4~7まで。
大変やけど見てってや。

前準備:データ読み込み

今回は、新しいPythonファイルで行っている。
前回の続きでもいいんだけど、長くなるからね。

f:id:DemRum:20180130213408j:plain

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#データの読み込み
df = pd.read_csv('test_u.csv')

#データのサイズ確認
df.shape

#データ先頭確認
df.head(3)

#データ抽出
r1 = df[[ '頭数','馬番','着順']]

まずは「pandas」と「numpy」をimport。これはデータ操作を簡単にするライブラリ。今回は少ししか使わんのやけど、こんなのあるんだ、ってことを見せるために使う。

この「pandas」のメソッドの「read_csv」。この一文で、csvの内容は「df」という変数に入ってもてる。すごいやん。 実行ファイルと同じフォルダにデータを入れている。このデータはTargetという競馬ソフトから出力している。興味がある方は別途調べてや。

「df.shape」でデータ数が表示されている。21393行で7列。
続く、「df.head(3)」で最初の3行が表示されている。こんなデータが入ってるで。
ササっと確認できるのが、jupyterの強みやね。

最後は「頭数」「馬番」「着順」以外のデータだけを抜き出している。この3つしか今回は使わんので。
これで「r1」って変数に抜き出したデータが入ってるんやで。

4.実際の過去の成績から、各出走頭数のレース数を求める

実は、この後の「5.」も同時に行えるんやけど、わかりやすさ優先で、まずは過去データの出走頭数ごとのレース数をカウントしよか。

f:id:DemRum:20180130213431j:plain

#リスト化
num_list = [0]*18

old = 0
for i in range(len(r1.index)):
    a = int(r1['頭数'][i])
    if(r1['着順'][i] == '1') :
        if(old==1) :     old = 2
        elif(old == 2):  old = 3
        else :           old = 1
    elif(r1['着順'][i] == '2') : 
        if(old==2):       old = 3
        else :            old = 2
    elif(r1['着順'][i] == '3') :    
        if(old == 3) :    old = 0
        else :            old = 3
    if(old == 3) : num_list[a-1] += 1

#出力確認用
num_list

ちょっとここはややこしいことしてるんやけど。まずは「r1」ってデータフレーム(型の名前ね)の'頭数'なり、'着順'の列のi番目のデータを取る、ということをやってる。
そこから操作してるんやけど、ここからはちょっとややこしい。蛇足やけど説明しておくと。

競馬には「同着」って事象があって。写真で見ようが何をしようが、どう見ても一緒にゴールしてるやん。っていうもの。
これがあると、2着が2頭とか、3着が2頭とかになっちゃうので、例えば2着が2頭だったら1着2着2着4着・・・ってなるのね。
そのあたりを回避するためにoldってところに前の情報が何着かってのを覚えて、それで分岐してる。

とりあえずそのレースの1~3着を確認できたら、その頭数のところのカウントを加算してる。

num_list[a-1] += 1

このところやね。

aってのは頭数が入ってるんやけど、配列は0から始まるので、例えば5頭立てで「5」だとしたら、配列では[4]のところに当たる。
[0]から数えて、5番目が[4]やからね。だから1引いてるのよ。

ここまでが各頭数のレース数カウント。

5.実際の過去の成績から、各出走頭数の足し算馬券の発生数を求める

f:id:DemRum:20180130213446j:plain

n = [0]*3
sum_list = [0]*18

#足し算判定用関数
def is_add_est(list):
    a = int(list[0])
    b = int(list[1])
    c = int(list[2])
    if( ((a+b)==c) or ((a+c)==b) or ((b+c)==a) ) :
        return True
    else :
        return False

old = 0
for i in range(len(r1.index)):
    a = int(r1['頭数'][i])  # a : 頭数が入る
    t = r1['馬番'][i]       # t : 馬番が入る
    if(r1['着順'][i] == '1') :
        n[old] = t
        old += 1
    elif(r1['着順'][i] == '2') : 
        n[old] = t
        old += 1
    elif(r1['着順'][i] == '3') : 
        if(old==2) : 
            n[old] = t
            old +=1
        else :
            old = 0
    if(old==3) : 
        if(is_add_est(n)) : sum_list[a-1] +=1        #判定後、加算
        old = 0
#出力確認用
sum_list

今回は少しは新しいことを、と思い関数を使ってみた。ここの部分ね。

def is_add_est(list):
    a = int(list[0])
    b = int(list[1])
    c = int(list[2])
    if( ((a+b)==c) or ((a+c)==b) or ((b+c)==a) ) :
        return True
    else :
        return False

「is_add_est」という関数にリスト型をぶち込んだら、その中の前3つが足し算になっているか判定してくれる関数。
前三つを、a,b,cという変数に入れて比較している。pythonではor演算は素直にorと書くので注意ね。
int型に変換しているところあるんだけど、ここで渡しているデータは「numpy.int64」という型になるんだけど、今は気にしなくてOK。
興味があったらpandasやnumpyのデータについて調べてみてや。今回は「csv読み込むのむっちゃ楽やで!」という紹介だけなので、深く突っ込みません。

で、この関数が「True」か「False」を返すのでそれを使って、足し算馬券ならカウント、という風に書いてるんよ。

   if(is_add_est(n)) : sum_list[a-1] +=1        #判定後、加算

あとはoldを添え字にして、着順ごとに馬番を入れていっています。初見だとわかりにくいかもしれませんが、同着を考慮した結果、このように書いています。
3着同着の場合は、1着2着3着3着と4頭になってしまうので、2番目の3着馬は無視しています。データ数的に与える影響は微量なので。

6.「4.」と「5.」より足し算の発生した実績値を求める

仕上げですね。

f:id:DemRum:20180130213505j:plain

per = [0]*18

for i in range(len(sum_list)):
    if(num_list[i]!=0) : per[i] = sum_list[i] / num_list[i] * 100
    else : per[i] = 0
#出力確認用
per

レース数で発生数を割って100をかけてるだけです。
特に目新しいものはないかな。次についでにグラフ化してみた。

f:id:DemRum:20180130213519j:plain

x=[0]*(18-4)
y=[0]*(18-4)

for i in range(4,18) :
    x[i-4]=i+1
    y[i-4]=per[i]
plt.plot(x,y)
plt.show()

横軸に頭数。縦軸に足し算馬券発生確率を表示してます。
参考までに、前回の記事で出した理論値のグラフを。

7.「3.」と「6.」の比較を行う

最後。先ほどのグラフで見比べられたところだけど、数字としては、「足し算馬券の出現確率は理論値より多いのか、少ないのか」という結論を出します。

f:id:DemRum:20180130213535j:plain

n = np.array(calc_per)
m = np.array(per)

m/n

「calc_per」には前回求めた理論値の確率が入ってるんよ。
「per」には先ほど求めた実データからの発生確率。
これをnumpyのアレイ型に変更して、そのまま割る。ほら簡単。

まとめ

出てきたデータの意味は、競馬の話なので、まぁよろしいやん。
詳しく知りたい場合は、ここを見てくれたらOK。

https://keiba-talk.com/?p=211

Pythonやるにしても、何か目的もって、何をしたいかってのが見えるように書きたいやんね、って書いた記事でした。
同じことしたい人(いないと思うけど)が居たときに、Pythonに興味持ってもらえたら嬉しい。
こちらも初心者なので、上級者からの指摘があれば嬉しいし、初心者の方も質問あったらコメントに書いてくれたらわかる範囲で答えるんで。
そして、面倒なので、関西弁やめるかも。やめないかも。