機械学習で競馬予想 其の009 ~回帰分析による予想システムの実装~
前回予想に使ったプログラムの実装は以下のとおりです。
loadHorseDataでtsvファイルを読込みdataShapingで読み込んだデータを回帰分析しやすいように整形して、回帰分析でパラメータを取得という流れになっています。
回帰分析の説明変数は、距離、馬番、馬体重、負担重量、目的変数はタイムとしています。回帰分析については、そのうち説明するかもしれませんが、今回は割愛します。
全ソース
# -*- coding: utf-8 -*- import scipy as sp import numpy as np from scipy import linalg as LA import os # 馬データの読み込み def loadHorseData(filename): horsedata = sp.genfromtxt(os.path.join(r"C:\Users\fumitaka\Desktop\blog\horse", filename), delimiter="\t", dtype=[ ('日付','U10'), # 0:日付 ('開催地','U10'), # 1:開催地 ('レース','i2'), # 2:レース ('レース名','U50'), # 3:レース名 ('距離','i4'), # 4:距離 ('天候','U10'), # 5:天候 ('馬番','i2'), # 6:馬番 ('人気','i3'), # 7:人気 ('着順','U10'), # 8:着順 ('タイム','U10'), # 9:タイム ('差/事故', 'i4'), # 10:差/事故 ('上3F','i4'), # 11:上3F ('通過順','U10'), # 12:通過順 ('体重','i4'), # 13:体重 ('騎手','U20'), # 14:騎手 ('負担重量','i4'), # 15:負担重量 ('調教師','U20'), # 16:調教師 ('獲得賞金(円)','U10') # 17:獲得賞金 ], converters={ 1 : lambda s: s.decode('utf8'), # 開催地 3 : lambda s: s.decode('utf8'), # レース名 5 : lambda s: s.decode('utf8'), # 天候 14 : lambda s: s.decode('utf8'), # 騎手 16: lambda s: s.decode('utf8'), # 調教師 }) return np.array(horsedata.tolist(), dtype = object) # データを整形する。 def dataShaping(horsedata): y = horsedata[:,9] # タイムの配列を作成 d = horsedata[:,4] # 距離の配列を生成 w1 = horsedata[:,13] # 体重の配列を生成 w2 = horsedata[:,15] # 負担重量の配列を生成 n = horsedata[:,6] # 馬番の配列を生成 # 記録が無いレースを除外 z = np.array([idx for idx, i in enumerate(y) if i != u'' ]) y = y[z] d = d[z] w1 = w1[z] w2 = w2[z] n = n[z] # タイムを数値変換 for idx, time in enumerate(y): if len(time.split(":")) == 2: y[idx] = np.float32(time.split(":")[0])*60+np.float32(time.split(":")[1]) else: y[idx] = np.float32(time) y = y.astype('float') # .Tは転置 return np.array([d, w1, w2, n, np.ones(len(n))]).T, y def getParam(filename): # 以下、main処理 horsedata = loadHorseData(filename) x, y = dataShaping(horsedata) return LA.lstsq(x, y)[0] # 偏回帰係数 def calctime(params, distance, weight1, weight2, no): t = np.int32(distance) * params[0] + np.int32(weight1) * params[1] + np.int32(weight2) * params[2] + np.int32(no) * params[3] + params[4] t1 = np.int32(distance) * params[0] + np.int32(weight2) * params[2] + np.int32(no) * params[3] + params[4] print str(t) + " = " + str(distance) + " * (" + str(params[0]) + ") + " + str(weight1) + " * (" + str(params[1]) + ") + " + str(weight2) + " * (" + str(params[2]) + ") + " + str(no) + " * (" + str(params[3]) + ") + " + str(params[4]) print "time = " + str(t1) + " + (" + str(params[1]) + ") * weight\n" return t # 8R print "8R 1200m" calctime(getParam(u"weekend.tsv"), 1200, 490, 54.0, 1) calctime(getParam(u"nikothankyou.tsv"), 1200, 490, 56.0, 2) calctime(getParam(u"syurudance.tsv"), 1200, 490, 55.0, 3) 以下、出走する馬の数だけcalctimeを実行するだけなので省略
それでは個々の実装について説明していきます。最初のloadHorseDataですが、機械学習 其の007で紹介したとおりです。次のdataShapingですが、説明変数を距離、馬体重、負担重量、馬番、目的変数をタイムとするので、loadHorseDataで読み込んだhorseDataから説明変数、目的変数となるものをそれぞれy,d,w1,w2,nの配列として取得しています。 取得した配列から落馬等の原因で記録が残っていないレースのものを除外しています。除外の方法ですが、単にタイムが無い(u''で比較)ものを除外するようにしています。
次に読み込んだhorseDataのタイムは、「1:14.7」のような表記となっているため単純な数値として処理するには不適切なので、これを数値に変換しています。ここで、数値変換の前に、if len(time.split(":") == 2という条件を追加しているのは、レースの距離が800mのように短いレースの場合1分を超えない記録が残っていることがあり、そういったデータの場合には、timeを":"でsplitしても、分の部分と秒の部分とで配列が分かれずエラーとなるため、splitするケースとしないケースをわけています。
そして、最後に[d, w1, w2, n]の配列を転置したものとy(タイム)を返却しています。
データ整形部分
# データを整形する。 def dataShaping(horsedata): y = horsedata[:,9] # タイムの配列を作成 d = horsedata[:,4] # 距離の配列を生成 w1 = horsedata[:,13] # 体重の配列を生成 w2 = horsedata[:,15] # 負担重量の配列を生成 n = horsedata[:,6] # 馬番の配列を生成 # 記録が無いレースを除外 z = np.array([idx for idx, i in enumerate(y) if i != u'' ]) y = y[z] d = d[z] w1 = w1[z] w2 = w2[z] n = n[z] # タイムを数値変換 for idx, time in enumerate(y): if len(time.split(":")) == 2: y[idx] = np.float32(time.split(":")[0])*60+np.float32(time.split(":")[1]) else: y[idx] = np.float32(time) y = y.astype('float') # .Tは転置 return np.array([d, w1, w2, n, np.ones(len(n))]).T, y
転置する前とした後のイメージが湧きにくいかもしれないので、念のためイメージを以下に示します。
転置前の配列の内容
[[1200 1200 1200 1200 1400 1400 1400 1400 1400 -1 1400 1400 1400 1400 1400 1400 1400 1300 1300 1600 1600 1200 -1] [502 496 493 501 500 499 493 490 494 493 499 498 493 491 495 501 502 506 509 498 500 486 482] [53 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54] [1 1 9 8 3 3 10 9 8 8 1 6 1 7 1 5 9 8 1 8 5 9 14] [1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0]]
転置後の配列の内容
[[1200 502 53 1 1.0] [1200 496 54 1 1.0] [1200 493 54 9 1.0] [1200 501 54 8 1.0] [1400 500 54 3 1.0] [1400 499 54 3 1.0] [1400 493 54 10 1.0] [1400 490 54 9 1.0] [1400 494 54 8 1.0] [-1 493 54 8 1.0] [1400 499 54 1 1.0] [1400 498 54 6 1.0] [1400 493 54 1 1.0] [1400 491 54 7 1.0] [1400 495 54 1 1.0] [1400 501 54 5 1.0] [1400 502 54 9 1.0] [1300 506 54 8 1.0] [1300 509 54 1 1.0] [1600 498 54 8 1.0] [1600 500 54 5 1.0] [1200 486 54 9 1.0] [-1 482 54 14 1.0]]
転置前の配列をAとしたとき、A[0]、A[1]でアクセスできるのは、それぞれ距離の配列、馬体重の配列となります。 これでも使えないことは無いのですが、レース単位でデータを処理することを考えると、転置後の配列(A’とします)のようにA'[0]で1つ目のレース情報となっていた方が、このあとで使うlstsqのパラメータとして使えるし、今後も何かと都合がよさそうなのでこのようにしています。(その都度転置しても良いので完全に好みの世界ですが、、、)
そしてdataShapingで得られた説明変数の配列と目的変数の配列をもとにしてlstsq(最小二乗法)を使い説明変数の係数(偏回帰係数)を求めています。ちなみに、lstsqの戻りの配列の1番目の要素が最小二乗法の解です。 詳しくはnumpy.linalg.lstsq — NumPy v1.9 Manualを参照してみてください。
回帰分析
def getParam(filename): # 以下、main処理 horsedata = loadHorseData(filename) x, y = dataShaping(horsedata) return LA.lstsq(x, y)[0] # 偏回帰係数
最期に、説明変数としていた、距離、馬体重、重量負担、馬番をパラメータとしてタイムを予測する関数calctimeを実装しています。馬体重だけは、レース開始の30分前くらいにならないと発表されないので、馬体重の関数となるような式をprintしているため冗長になっていますが、その辺は気にしないでください。
タイム予想
def calctime(params, distance, weight1, weight2, no): t = np.int32(distance) * params[0] + np.int32(weight1) * params[1] + np.int32(weight2) * params[2] + np.int32(no) * params[3] + params[4] t1 = np.int32(distance) * params[0] + np.int32(weight2) * params[2] + np.int32(no) * params[3] + params[4] print str(t) + " = " + str(distance) + " * (" + str(params[0]) + ") + " + str(weight1) + " * (" + str(params[1]) + ") + " + str(weight2) + " * (" + str(params[2]) + ") + " + str(no) + " * (" + str(params[3]) + ") + " + str(params[4]) print "time = " + str(t1) + " + (" + str(params[1]) + ") * weight\n" return t
次回はこの予想システムで実際に馬券を買ってみたのでその報告と結果分析を行おうと考えています。
jbpm備忘録5 ESBアクションのインスタンス
enchantMoonでメモしてみるシリーズ3弾。
JBOSS ESBのアクションのインスタンスはアクションごとに1つだけという内容のメモ。
インスタンスが1つなので、ESBアクション内にフィールドを保持することは原則非常に危険。synchronizedとかでフィールドを保護することも考えられるが、そのような実装だとパフォーマンスを著しく損なう上に、同じESBサービスを複数のスレッドから呼び出した場合に1つのスレッドで遅延が発生すると他のスレッドも巻き込んで根こそぎ遅延する。
従ってそのような実装はお勧めできない。
機械学習で競馬予想 其の008 ~結果分析と更に予想~
タイトルを「機械学習 ~其のXXX~」から実態に合わせて「機械学習で競馬予想 ~其のXXX~」に変えました。
先日のエントリで分析したトップライジングですが、結果は、10着でタイムは1:15.7(75.7秒)という結果に終わり惨敗でした。
先日の分析では、タイムも74秒代で1着を十分狙えるだろうと考えていただけに残念。
10着馬(トップライジング)の開催日別タイム
ここで今回、1着だった馬のデータを同様に解析したものを見てみます。
1着馬(シュヤク)の開催日別タイム
ベストのタイムがシュヤクとトップライジングとで、それぞれ73秒と74.3秒とで大きく違いますが、比べてみても良くわからないため、取りあえず、馬体重、重量負担、馬番を追加して回帰分析してみました。 その結果は以下のとおりです。
これは、20150918の大井競馬 8レースから12レースの各馬の暫定予想タイムになっています。暫定というのは、このデータを取ったタイミングで、馬体重が公表されておらず、暫定で490kgを設定しているためです。
8R 1200m 87.5201280444 = 1200 * (-0.00608170020752) + 490 * (-0.0855814790549) + 54.0 * (2.52359450254) + 1 * (0.478989892862) time = 129.455052781 + (-0.0855814790549) * weight 74.8910383433 = 1200 * (0.0674028008163) + 490 * (0.043545588983) + 56.0 * (-0.495432712341) + 2 * (0.207285326593) time = 53.5536997417 + (0.043545588983) * weight 74.9022649867 = 1200 * (0.0797921854474) + 490 * (0.0707924791712) + 55.0 * (-1.00324819042) + 3 * (-0.119340623601) time = 40.2139501928 + (0.0707924791712) * weight 72.6155958233 = 1200 * (0.0723753265839) + 490 * (0.0553274071246) + 56.0 * (-0.739853836204) + 4 * (0.0216473147644) time = 45.5051663323 + (0.0553274071246) * weight 77.7753049948 = 1200 * (0.0717252584652) + 490 * (-0.0078180068587) + 56.0 * (-0.0888651292774) + 5 * (0.102453087363) time = 81.6061283556 + (-0.0078180068587) * weight 74.6251760234 = 1200 * (0.0799253840792) + 490 * (-0.0248266240931) + 56.0 * (-0.163810847023) + 6 * (0.00886139453298) time = 86.790221829 + (-0.0248266240931) * weight 78.0259506402 = 1200 * (0.0792853449902) + 490 * (-0.299383884159) + 54.0 * (2.39423611011) + 7 * (0.0418414205825) time = 224.724053878 + (-0.299383884159) * weight 79.0381926366 = 1200 * (0.0646107009093) + 490 * (0.0514334046089) + 54.0 * (-0.424217992352) + 8 * (-0.0986556407497) time = 53.8358243782 + (0.0514334046089) * weight 73.080599263 = 1200 * (0.0756171545588) + 490 * (-0.0633117461005) + 56.0 * (0.229545656756) + 9 * (0.0564680670304) time = 104.103354852 + (-0.0633117461005) * weight 76.8909480018 = 1200 * (0.0736970011344) + 490 * (-0.00802184168096) + 56.0 * (-0.141276728437) + 10 * (0.0296745856668) time = 80.8216504255 + (-0.00802184168096) * weight 77.1498916177 = 1200 * (0.075142853651) + 490 * (0.0169685308434) + 54.0 * (-0.398624803746) + 11 * (0.0172387750474) time = 68.8353115044 + (0.0169685308434) * weight 75.4531374072 = 1200 * (0.0749265448252) + 490 * (0.00612468085151) + 56.0 * (-0.304055655761) + 12 * (-0.036057773136) time = 72.45204379 + (0.00612468085151) * weight 81.6638557379 = 1200 * (0.0749308989762) + 490 * (0.0859239691663) + 54.0 * (-0.919754803964) + 13 * (-0.0530160393122) time = 39.5611108464 + (0.0859239691663) * weight 9R 1600m 103.86577985 = 1600 * (0.0726438344989) + 490 * (-0.0218674539464) + 56.0 * (-0.0280404848658) + 1 * (-0.0790357623769) time = 114.580832283 + (-0.0218674539464) * weight 105.001932535 = 1600 * (0.0696821412552) + 490 * (0.0669686378066) + 54.0 * (-0.729869812855) + 2 * (0.0544219478591) time = 72.1873000098 + (0.0669686378066) * weight 105.142058319 = 1600 * (0.0702696797711) + 490 * (0.00581458692839) + 56.0 * (-0.178397239763) + 3 * (-0.0494438277566) time = 102.292910724 + (0.00581458692839) * weight 104.385990573 = 1600 * (0.0693722815285) + 490 * (0.0511174505049) + 56.0 * (-0.56485975734) + 4 * (-0.00626605231626) time = 79.3384398253 + (0.0511174505049) * weight 102.195931185 = 1600 * (0.0717427792242) + 490 * (0.0792932180769) + 56.0 * (-0.901536873127) + 5 * (-0.192025507265) time = 63.3422543273 + (0.0792932180769) * weight 105.967347615 = 1600 * (0.0712976748168) + 490 * (-0.0414219431634) + 56.0 * (0.221069824247) + 6 * (-0.0320150165328) time = 126.264099765 + (-0.0414219431634) * weight 102.466741059 = 1600 * (0.0684971551098) + 490 * (-0.0492030845349) + 56.0 * (0.31262544514) + 7 * (-0.0751743746671) time = 126.576252481 + (-0.0492030845349) * weight 102.625803731 = 1600 * (0.0724653892123) + 490 * (-0.058596869242) + 54.0 * (0.293476844288) + 8 * (-0.0567628339865) time = 131.338269659 + (-0.058596869242) * weight 102.008954504 = 1600 * (0.0724128103182) + 490 * (-0.0612527219682) + 54.0 * (0.28939936301) + 9 * (0.0594140174659) time = 132.022788269 + (-0.0612527219682) * weight 105.083153821 = 1600 * (0.0749321727016) + 490 * (-0.0540842740235) + 54.0 * (0.221160074921) + 10 * (-0.0249672276314) time = 131.584448092 + (-0.0540842740235) * weight 103.608431996 = 1600 * (0.0737408098649) + 490 * (-0.0697242623347) + 56.0 * (0.348650436415) + 11 * (0.0239636651977) time = 137.77332054 + (-0.0697242623347) * weight 101.965789104 = 1600 * (0.0702263226535) + 490 * (-0.0499492296608) + 53.0 * (0.264687290088) + 12 * (0.00419741810974) time = 126.440911638 + (-0.0499492296608) * weight 102.819103916 = 1600 * (0.0721936874656) + 490 * (-0.0427528869553) + 56.0 * (0.15586169725) + 13 * (-0.0361643435671) time = 123.768018525 + (-0.0427528869553) * weight 113.735757207 = 1600 * (0.00602666002174) + 490 * (-0.811583161982) + 56.0 * (8.96756608515) + 14 * (-0.0296321589512) time = 511.411506578 + (-0.811583161982) * weight 10R 1200m 75.6534978444 = 1200 * (0.0758249746465) + 490 * (0.0865955387581) + 56.0 * (-1.03137918365) + 1 * (-0.0110514387177) time = 33.2216838529 + (0.0865955387581) * weight 78.5825230819 = 1200 * (0.0785819595262) + 490 * (0.0960475103623) + 56.0 * (-1.12425321453) + 2 * (0.0895357932475) time = 31.5192430044 + (0.0960475103623) * weight 79.4834806527 = 1200 * (0.0660203710677) + 490 * (0.0548407883321) + 54.0 * (-0.487107813385) + 3 * (-0.103042996191) time = 52.6114943699 + (0.0548407883321) * weight 77.2240682948 = 1200 * (0.0764763083184) + 490 * (-0.0691273210283) + 56.0 * (0.35731868139) + 4 * (-0.171240135337) time = 111.096455599 + (-0.0691273210283) * weight 81.3518240972 = 1200 * (0.0688353655261) + 490 * (0.13678367073) + 56.0 * (-1.20407747812) + 5 * (-0.169254883413) time = 14.3278254397 + (0.13678367073) * weight 78.7843083065 = 1200 * (0.0892981962737) + 490 * (-0.200840504708) + 54.0 * (1.25273144361) + 6 * (0.398470354988) time = 177.196155614 + (-0.200840504708) * weight 80.6921887286 = 1200 * (0.0754731721705) + 490 * (0.0840634396165) + 54.0 * (-0.946776093605) + 7 * (0.00845796665483) time = 39.5011033165 + (0.0840634396165) * weight 75.78258311 = 1200 * (0.0677149483788) + 490 * (0.082076442838) + 54.0 * (-0.833401815472) + 8 * (-0.0861392374537) time = 35.5651261194 + (0.082076442838) * weight 74.7007243051 = 1200 * (0.0815805663472) + 490 * (-0.0281168195522) + 54.0 * (-0.15658824648) + 9 * (-0.106994269) time = 88.4779658857 + (-0.0281168195522) * weight 74.0807696876 = 1200 * (0.0788362316355) + 490 * (-0.0239889151471) + 56.0 * (-0.159927788029) + 10 * (0.018781627663) time = 85.8353381097 + (-0.0239889151471) * weight 70.9933516161 = 1200 * (0.0713940008831) + 490 * (0.144449906112) + 56.0 * (-1.50354918028) + 11 * (-0.114649940253) time = 0.212897621379 + (0.144449906112) * weight 84.1289572641 = 1200 * (0.0558304719911) + 490 * (0.112778196973) + 56.0 * (-0.701292784865) + 12 * (0.0952891925219) time = 28.8676407471 + (0.112778196973) * weight 75.2985017929 = 1200 * (0.0674810778737) + 490 * (-0.0115957903982) + 54.0 * (0.00468991293807) + 13 * (-0.0192392045457) time = 80.980439088 + (-0.0115957903982) * weight 11R 1600m 103.556626742 = 1600 * (0.0723732373755) + 490 * (-0.0487422332652) + 57.0 * (0.206593565492) + 1 * (-0.132691992063) time = 127.440321042 + (-0.0487422332652) * weight 102.236125099 = 1600 * (0.069514078991) + 490 * (-0.00871246780474) + 55.0 * (-0.0871276186781) + 2 * (0.0373634822802) time = 106.505234323 + (-0.00871246780474) * weight 103.205254569 = 1600 * (0.0685235750555) + 490 * (0.0140464709482) + 57.0 * (-0.230866930339) + 3 * (-0.0519404182504) time = 96.3224838048 + (0.0140464709482) * weight 102.671368475 = 1600 * (0.0695700260522) + 490 * (0.000284212518471) + 57.0 * (-0.153490474486) + 4 * (-0.00774507425394) time = 102.532104341 + (0.000284212518471) * weight 100.29625964 = 1600 * (0.0680543356651) + 490 * (0.0600271085077) + 57.0 * (-0.665653995703) + 5 * (-0.0123365675779) time = 70.8829764712 + (0.0600271085077) * weight 102.412176761 = 1600 * (0.0728753516771) + 490 * (-0.0159254966855) + 55.0 * (-0.118679701286) + 6 * (0.0237485040393) time = 110.215670137 + (-0.0159254966855) * weight 102.746262197 = 1600 * (0.0696908750778) + 490 * (-0.127176872227) + 55.0 * (0.975661097602) + 7 * (-0.014832986347) time = 165.062929588 + (-0.127176872227) * weight 102.159513383 = 1600 * (0.0740656025914) + 490 * (0.00893022163509) + 57.0 * (-0.346461094749) + 8 * (-0.121622120504) time = 97.7837047815 + (0.00893022163509) * weight 102.627822361 = 1600 * (0.0693956184081) + 490 * (0.00835914768876) + 57.0 * (-0.234643871134) + 9 * (0.0970612439065) time = 98.5318399934 + (0.00835914768876) * weight 12R 1800m 114.311749262 = 1800 * (0.0661093024384) + 490 * (-0.0689679076109) + 53.0 * (0.544673581437) + 1 * (0.241579785641) time = 148.106023991 + (-0.0689679076109) * weight 118.134687196 = 1800 * (0.0708635076132) + 490 * (0.0497348668533) + 56.0 * (-0.596738023274) + 2 * (-0.186190981037) time = 93.7646024383 + (0.0497348668533) * weight 115.722414038 = 1800 * (0.0627981255485) + 490 * (-0.0737046602742) + 56.0 * (0.693255689789) + 3 * (-0.00708234778356) time = 151.837697572 + (-0.0737046602742) * weight 110.218202951 = 1800 * (0.0558387358784) + 490 * (0.0842304586098) + 56.0 * (-0.554070302816) + 4 * (-0.134127347797) time = 68.9452782323 + (0.0842304586098) * weight 115.72432809 = 1800 * (0.0652500580749) + 490 * (0.003004280024) + 56.0 * (-0.0401534891509) + 5 * (-0.189855652892) time = 114.252230878 + (0.003004280024) * weight 119.882310196 = 1800 * (0.0737906753503) + 490 * (-0.00889739468575) + 56.0 * (-0.162168956544) + 6 * (0.083379921261) time = 124.242033592 + (-0.00889739468575) * weight 118.465310363 = 1800 * (0.0791376753605) + 490 * (0.0852668174952) + 54.0 * (-1.22079806111) + 7 * (0.0228356344157) time = 76.6845697899 + (0.0852668174952) * weight 113.272925169 = 1800 * (0.0670640117924) + 490 * (0.256597179991) + 56.0 * (-2.38236267711) + 8 * (0.0296744581617) time = -12.4596930264 + (0.256597179991) * weight 117.500044468 = 1800 * (0.0682065454219) + 490 * (-0.0431373427755) + 56.0 * (0.33024329199) + 9 * (-0.292007075832) time = 138.637342428 + (-0.0431373427755) * weight 117.111881561 = 1800 * (0.0671580701417) + 490 * (1.66744887632e-06) + 54.0 * (-0.0497372595788) + 10 * (-0.108764972664) time = 117.111064511 + (1.66744887632e-06) * weight 114.999647899 = 1800 * (0.0663582628951) + 490 * (0.0651121760702) + 56.0 * (-0.637567237164) + 11 * (-0.0587660277937) time = 83.0946816244 + (0.0651121760702) * weight 116.010184727 = 1800 * (0.0688308475348) + 490 * (-0.0300615616672) + 54.0 * (0.129175344862) + 12 * (-0.0108870200623) time = 130.740349944 + (-0.0300615616672) * weight 116.128284199 = 1800 * (0.067983100568) + 490 * (-0.0592334672935) + 55.0 * (0.425862954324) + 13 * (-0.0491815643766) time = 145.152683173 + (-0.0592334672935) * weight
実装の紹介は後日。
jbpm備忘録4 ActionHandler内のstaticオブジェクト
enchantMoonでメモしてみるシリーズ2弾。
ActionHandler内にstaticなオブジェクトを定義した場合に、そのオブジェクトがどこまで共有されるかを実験してみた。
以下はその時の結果をメモ。
結論としては、プロセス内だけで共有される。つまり同じ定義のプロセスであってもインスタンスが違えば別物として扱われるということになる。
機械学習 其の007 ~馬毎のデータ分析~
前回のエントリでは1200mレースの着順事のタイムレンジを分析することで、1着の馬のタイム期待値を求めようとしてみましたが、レンジ幅が大きすぎていまいちな結果となったので、今回は馬のデータについて分析してみようと思います。
データは以下のような感じです。 今回は、開催日毎のタイムで分析をしてみたいと思います。
データの元ネタは例によってnankankeiba.comから取得させて頂きました。
データを見ると開催日は第1カラム、距離は第5カラム、タイムは第10カラム目となっています。
馬の戦績データ
15/8/13 大井 3 C3(六)(七) 1200 曇/稍重 7 1 2/12 1:14.3 0.5 37.5 1-1 446 西啓太 54.0 橋本馬 240,000 15/7/28 大井 3 C3(八)(九)(十) 1200 晴/良 12 1 2/14 1:15.0 0.2 39.1 3-3 446 西啓太 54.0 橋本馬 240,000 15/6/26 大井 1 C2(十五)C3(一) 1200 曇/良 14 9 4/14 1:14.7 0.2 38.3 3-3 447 西啓太 55.0 橋本馬 120,000 15/6/4 大井 6 C2(十六)C3(一) 1200 晴/稍重 9 10 8/10 1:15.0 1.0 38.0 3-3 443 西啓太 55.0 橋本馬 0 15/1/23 大井 7 C2(十五)(十六)(十七) 1200 晴/不良 3 9 10/16 1:16.4 2.9 40.7 8-9 447 中村尚 56.0 橋本馬 0 14/12/28 大井 3 3歳190万 1200 晴/良 10 8 3/14 1:15.3 0.5 38.4 4-4 450 西啓太 53.0 橋本馬 180,000 14/11/26 大井☆ 4 3歳150万 1200 雨/不良 4 6 1/15 1:16.1 0.2 40.2 3-1 451 西啓太 53.0 橋本馬 1,000,000 14/9/29 大井 3 3歳115万 1200 晴/良 7 2 3/14 1:15.4 0.4 38.2 6-5 446 西啓太 53.0 橋本馬 198,000 14/8/25 大井 2 3歳95万 1200 曇/良 1 2 5/14 1:16.4 0.8 38.4 9-8 437 西啓太 53.0 橋本馬 110,000 14/8/12 大井 3 3歳70万 1200 雨/稍重 6 2 5/12 1:15.7 0.7 38.7 7-8 437 西啓太 53.0 橋本馬 110,000 14/7/27 大井 2 3歳55万 1200 曇/良 11 10 3/14 1:16.0 0.7 38.9 7-7 431 西啓太 53.0 橋本馬 198,000 14/2/25 大井 3 3歳35万 1200 晴/良 8 7 3/14 1:17.5 2.2 39.9 8-7 436 千田洋 56.0 橋本馬 240,000 14/2/3 大井 4 3歳25万 1500 晴/良 7 7 9/12 1:42.4 1.8 42.9 8-7-8 440 千田洋 56.0 橋本馬 0 14/1/20 大井 4 3歳25万 1200 晴/良 4 7 6/10 1:18.5 1.2 40.7 8-8 443 千田洋 56.0 橋本馬 0
分析につかったプログラム
# -*- coding: utf-8 -*- import scipy as sp import numpy as np import matplotlib.pyplot as plt import datetime from matplotlib.font_manager import FontProperties # 馬データの読み込み horsedata = sp.genfromtxt(r"toprising.tsv", delimiter="\t", dtype=[ ('日付','U10'), # 0:日付 ('開催地','U10'), # 1:開催地 ('レース','i2'), # 2:レース ('レース名','U50'), # 3:レース名 ('距離','i4'), # 4:距離 ('天候','U10'), # 5:天候 ('馬番','i2'), # 6:馬番 ('人気','i3'), # 7:人気 ('着順','U10'), # 8:着順 ('タイム','U10'), # 9:タイム ('差/事故', 'i4'), # 10:差/事故 ('上3F','i4'), # 11:上3F ('通過順','U10'), # 12:通過順 ('体重','i4'), # 13:体重 ('騎手','U20'), # 14:騎手 ('負担重量','i4'), # 15:負担重量 ('調教師','U20'), # 16:調教師 ('獲得賞金(円)','U10') # 17:獲得賞金 ], converters={ 1 : lambda s: s.decode('utf8'), # 開催地 3 : lambda s: s.decode('utf8'), # レース名 5 : lambda s: s.decode('utf8'), # 天候 14 : lambda s: s.decode('utf8'), # 騎手 16: lambda s: s.decode('utf8'), # 調教師 }) horsedata = np.array(horsedata.tolist(), dtype = object) x = horsedata[:,0] # 開催日の配列を生成 y = horsedata[:,9] # タイムの配列を作成 z = horsedata[:,4] # 距離の配列を生成 # 1200m以外のレースを除外 z = np.array([idx for idx, i in enumerate(z) if i == 1200 ]) x = x[z] y = y[z] # 日付を数値変換 for idx, d in enumerate(x): yyyy = "20" + d.split('/')[0] mm = d.split('/')[1] dd = d.split('/')[2] if len(mm) == 1: mm = "0" + mm if len(dd) == 1: dd = "0" + dd x[idx] = datetime.datetime.strptime(yyyy + mm + dd, '%Y%m%d') # タイムを数値変換 for idx, time in enumerate(y): y[idx] = np.float32(time.split(":")[0])*60+np.float32(time.split(":")[1]) y = y.astype('float') # 描画 xticks = [datetime.datetime(2010,1,1), datetime.datetime(2010,4,1), datetime.datetime(2010,7,1), datetime.datetime(2010,10,1), datetime.datetime(2011,1,1), datetime.datetime(2011,4,1), datetime.datetime(2011,7,1), datetime.datetime(2011,10,1), datetime.datetime(2012,1,1), datetime.datetime(2012,4,1), datetime.datetime(2012,7,1), datetime.datetime(2012,10,1), datetime.datetime(2013,1,1), datetime.datetime(2013,4,1), datetime.datetime(2013,7,1), datetime.datetime(2013,10,1), datetime.datetime(2014,1,1), datetime.datetime(2014,4,1), datetime.datetime(2014,7,1), datetime.datetime(2014,10,1), datetime.datetime(2015,1,1), datetime.datetime(2015,4,1), datetime.datetime(2015,7,1), datetime.datetime(2015,10,1) ] fp = FontProperties(fname=r'C:\WINDOWS\Fonts\msgothic.ttc', size=14) plt.scatter(x, y) plt.title(u"開催日別タイム", fontproperties=fp) plt.xlabel(u"開催日", fontproperties=fp) plt.ylabel(u"タイム", fontproperties=fp) plt.xticks(xticks, [str(d.year) + "/" + str(d.month) for d in xticks], fontproperties=fp) # 72ヵ月のレンジでx軸を作成 plt.yticks([i for i in range(70, 100)], [u"%i秒"%i for i in range(70, 100)], fontproperties=fp) # 70秒から100秒のレンジでy軸を作成 plt.autoscale(tight=True) plt.grid() plt.show()
プログラムの実行結果は以下のとおりです。レースを重ねるごとにタイムが伸びているのがわかります。1200mのレースであれば、前回のエントリからも分かるように73~74秒代のタイムを出せれば十分に1,2着を狙えると考えても良いと思います。
ちなみに、今回のデータは、今日(20150916の大井競馬場の第2レースに出走するトップライジングという馬です。
次回は分析に使ったプログラムの説明と、このレース結果についての分析を行おうと思います。
機械学習 其の006 ~前処理とデータ表示3~
前回までは単に1200mのレースに絞ってデータを分析していましたが、今回は更に1200mのレースでも一般のレースに絞ってデータを分析してみたいと思います。 どういうことかというと、前回のレースは2歳限定、3歳限定といったレースのものも全部混ぜていたのですが、これは人間で言ってみると、6歳児と7歳児(馬の場合だともっと?)の100m走の記録を比較するようなもので、意味がないと言うか、いい加減すぎたので、この点を改めて再分析してみます。
例によってtsvとしてデータを用意します。今回のデータでは、大井競馬場の2015年の8月開催の1200mレースの中で、「サラブレッド系 一般 別定」となっているレースのみを対象としました。
用意したデータを前回のエントリと同じプログラムで処理してみると、以下のような結果が得られました。
実行結果
みてのとおりですが、あまり意味がなさそうです。今回想定した軸だけでは分析するにはまだまだ厳しいのかもしれません。
jbpm備忘録3 forkのスレッド。
jBPMがらみでいくつか纏めておくこともあるので、enchantMoonを使いつつメモを作成した。
fork時にfork先がそれぞれ別のスレッドで実行されることについてのメモ。
fork後に分岐するルートの各ノードは別々のスレッドで実行されるため、fork前に保持していたプロセス変数を操作する場合、プロセス変数の取り扱いに先立ってプロセスのロックが必要になる。