How many files(0-15)

競馬の予想システムで一儲を企むおっさんのヨコシマな横顔

機械学習で競馬予想 其の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つのスレッドで遅延が発生すると他のスレッドも巻き込んで根こそぎ遅延する。
従ってそのような実装はお勧めできない。
f:id:taka23kz:20131205002152j:plain

機械学習で競馬予想 其の008 ~結果分析と更に予想~

タイトルを「機械学習 ~其のXXX~」から実態に合わせて「機械学習で競馬予想 ~其のXXX~」に変えました。

先日のエントリで分析したトップライジングですが、結果は、10着でタイムは1:15.7(75.7秒)という結果に終わり惨敗でした。
先日の分析では、タイムも74秒代で1着を十分狙えるだろうと考えていただけに残念。


10着馬(トップライジング)の開催日別タイム
f:id:taka23kz:20150916020954p:plain


ここで今回、1着だった馬のデータを同様に解析したものを見てみます。


1着馬(シュヤク)の開催日別タイム
f:id:taka23kz:20150917000502p:plain


ベストのタイムがシュヤクとトップライジングとで、それぞれ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なオブジェクトを定義した場合に、そのオブジェクトがどこまで共有されるかを実験してみた。
以下はその時の結果をメモ。

結論としては、プロセス内だけで共有される。つまり同じ定義のプロセスであってもインスタンスが違えば別物として扱われるということになる。
f:id:taka23kz:20131205002139j:plain

機械学習 其の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レースに出走するトップライジングという馬です。

f:id:taka23kz:20150916020954p:plain


次回は分析に使ったプログラムの説明と、このレース結果についての分析を行おうと思います。

機械学習 其の006 ~前処理とデータ表示3~

前回までは単に1200mのレースに絞ってデータを分析していましたが、今回は更に1200mのレースでも一般のレースに絞ってデータを分析してみたいと思います。 どういうことかというと、前回のレースは2歳限定、3歳限定といったレースのものも全部混ぜていたのですが、これは人間で言ってみると、6歳児と7歳児(馬の場合だともっと?)の100m走の記録を比較するようなもので、意味がないと言うか、いい加減すぎたので、この点を改めて再分析してみます。

例によってtsvとしてデータを用意します。今回のデータでは、大井競馬場の2015年の8月開催の1200mレースの中で、「サラブレッド系 一般 別定」となっているレースのみを対象としました。

用意したデータを前回のエントリと同じプログラムで処理してみると、以下のような結果が得られました。


実行結果
f:id:taka23kz:20150914235920p:plain


みてのとおりですが、あまり意味がなさそうです。今回想定した軸だけでは分析するにはまだまだ厳しいのかもしれません。

jbpm備忘録3 forkのスレッド。

jBPMがらみでいくつか纏めておくこともあるので、enchantMoonを使いつつメモを作成した。

fork時にfork先がそれぞれ別のスレッドで実行されることについてのメモ。
fork後に分岐するルートの各ノードは別々のスレッドで実行されるため、fork前に保持していたプロセス変数を操作する場合、プロセス変数の取り扱いに先立ってプロセスのロックが必要になる。
f:id:taka23kz:20131205002132j:plain