続・競馬であそぶ 3

 楽して儲けてイイことないというが、嘘だと思う 




9. 偏差値 

騎手の技量を数値で示すという試みは最初の頃の意味と少しづつズレてきてはいるが、ある
程度の目的は達していると思う。
下手な騎手は、数値差だけタイムが余計かかるということと致命的な失策を犯す事が多い。
巧い騎手は速く走らせる他にも馬にレースを教えるのが上手だ。
でも関東の某S騎手なんかはソツなく乗るが、何かが欠けているようで面白くもオカシクもない。
夢もない、華もない。そして、ココまでは偏差値とは関係なし。


このところ指数とオッズとを比較して買い目を検討しているが、それなら指数を偏差値にして
からの方が収まりがイイということでテストしている。
あくまでも予想指数を偏差値化するのであって、レース毎の走破タイムや評価指数をどうこう
したいと思っているわけではない。意味があるのかどうかにも興味がない。

現在の自分のやり方を効果( 的中率 or 回収率 )で超える可能性があるかもしれない、という
ことでテストしている。
要するに、平均値と標準偏差を出しておけば使えるので、サブルーチンを書いた。
2006.05.26 指摘を受けて修正
2006.06.10 指摘を受けて致命的ミスを修正

# 偏差 = INDEX - 平均値 ;	偏差値 = 10 * ( 偏差 / 標準偏差 ) + 50 ;
# 引数は配列のリファレンス。
# ex. &mk_hensa( \@hairetu )
# 配列そのもので返す場合は、return @ans = ( $ave, $hhs ) とする。
sub mk_hensa {                  # 偏差値データ[ 平均値・標準偏差 ]
    my $hr = shift ;            # 配列のリファレンス
    my $nn = 0 ;                # 対象数 加算用
    my $ans ;
    my ( $ave, $bsn, $hhs ) = () ;
    my $sum = 0 ;
    for my $i ( @$hr ) {
        next unless $i ;
        $sum += $i ;                   # 単純合計
        $nn++ ;
    }
    $ave = $sum / $nn if $nn ;         # 平均値
    my $jsum = 0 ;
    for my $i ( @$hr ) {
        my $sa = $i - $ave ;
        $jsum += $sa * $sa ;           # 差の二乗計
    }
    $bsn = $jsum / $nn if $nn ;        # 分散
    $hhs = sqrt $bsn ;                 # 標準偏差
    $ans = [ $ave, $hhs ] ;     # 平均と標準偏差のリファレンス
    return $ans ;
}

使い方は以下参照。

    my $hensael = &mk_hensa( \@hairetu ) ;      # [ 平均値・標準偏差 ]

    # .....
    # my $index = 〜 ;
    #.....

    # 偏差 = INDEX - 平均値 ;   偏差値 = 10 * ( 偏差 / 標準偏差 ) + 50 ;
    my ( $ave, $hhs ) = @$hensael ;
    my $hensa = $index - $ave ;
    my $hensachi = 10 * ( $hensa / $hhs ) + 50 ;



DM 値も偏差値にしてからの方が使いやすそうだ。
DM 値を取得するときの一例。sSeia は実際に以下のような処理をしている。
但し、このなかで TARGET の外部指数が現在は整数値しか使えないので、10倍し て3桁の整数
にしている。こちらの効果については未検証。
当然、このままでは使えない。dm2s は100分の1秒に変換するサブルーチン。
予め初期化すべき変数や、ファイルハンドルの open など、自分の環境に応じて書き換えること。

記事変更及び追加説明:( 2008.02.29 )( すでにDM値への興味を失っているので記憶を頼りに、、 )

以下の場合では、{ }内でだけ使われる変数は $rt_bt など。更にそれ以下の { } 内でも $ave など。
{ } の外でも使いたい変数は { } の外で初期化する必要があります。例えば、@dmj や $dmtop 。
open するファイルが実在するか確認すること。下の場合は $others $yyyy $yymmdd などの変数は他でセットされて
いて、指定されたフォルダの指定されたファイルを open しに行きます。ここでは jvopt での指定と多分同じ。

そのほか、必要な変数は距離( $ky )とレースコード( $racecode )の予めのセットが必要ですね。

dm2s と sort_kj はサブルーチンで & を頭につけて実行しています。
他の項目とダブるけれど、ここにも出しておきます。
必要ない部分は # でコメントアウトをしてください。


my ( @dmd, @dmj, $dmtop ) ;

{
    @dmd = () ;
    @dmj = () ;
    $dmtop = '' ;
    
    my $rt_bt = "$others/$yyyy/0B13$yymmdd\.dat" ; 
    next unless -e $rt_bt ;
    open DAT, $rt_bt ;
    while ( <DAT> ) {
        chomp ;
        $do2->() ;
        my $ave = 0 ;       # 平均値
        my $bsn = 0 ;       # 分散
        my $hhs = 0 ;       # 標準偏差
        my $max = 99999 ;
        my $sum = 0 ;
        my $jjw = 0 ;
        my ( $racecode, $data ) = unpack '@11 A16 @31 A270', $_ ;
        my @dmtm =  unpack 'A15' x 18, $data ;
        for my $ln ( @dmtm ) {
            chomp ;
            next unless $ln ;
            my ( $ub, $tm ) = unpack '@0 A2 @2 A5', $ln ;
            my $ttm = &dm2s( $tm ) ;            # 1/100秒に換算
            $ttm = 6000 * $ky / $ttm ;          # 分速で計算する
            next unless ( $ub and $ttm ) ;
            $max = $tm if $max > $tm ;
            $dmd[$ub] = $ttm ;
            $sum += $ttm ;
            $jjw += $ttm * $ttm ;
        }
        $ave = $sum / $to ;
        my $sumw = $sum * $sum / $to ;
        $bsn = ( $jjw - $sumw ) / $to ;
        $hhs = sqrt $bsn ;
        for my $dm ( @dmd ) {
            my $hns = $dm - $ave ;
            $dm = ( $hns / $hhs ) * 10 + 50 ;
        }
                @dmj = &sort_kj( @dmd ) ;       # 降順ソート
        $dmd[0] = $racecode ;
        my $mix = &dm2s( $max ) ;
        my ( $m1, $m2, $m3 ) = unpack 'A1A2A2', $max ;
        $m1 = join '.', ( $m1 ? ( $m1, $m2, $m3 ) : ( $m2, $m3 ) ) ;
        $m2 = 6 * $mix / $ky ;
        # ↓ 出馬表に想定タイムとして表示するために
        $dmtop = sprintf " 想定: %s ( 3F: %.1f )", $m1, $m2 ;
    }
    close DAT ;
}

sub dm2s {                   # DM値(時計表示)などを 1/100 秒に換算(汎用)
    my $aa = shift;    $aa =~ s/[^0-9]//g;     my $ans;
    my ( $w1, $w2 ) = unpack 'A1A4', $aa ;
    $ans = $w1 * 6000 + $w2 ;
    return $ans;
}

sub sort_kj {   # 降順ソート順位
    my @hr = @_ ;           # 引数は配列
    my @sorted = sort { $b <=> $a }
                 grep { $_ > 0 } @hr ;
    my $i ;
    my @jun ;
    my %kj ;
    my $num = 1 ;
    my $non = -99999 ;       # 存在しないはずの数値をセット
    for $i ( @sorted ) {
        if ( $i != $non ) {
            $kj{$i} = $num ;
            $non = $i ;
        }
        $num++ ;
    }
    # 最初の配列と比較しながら、@jun という配列を作る。
	# 馬番( $i )順に順位を入れている。
    for $i ( 1..$#hr ) {
        next if $hr[$i] == 0 ;
        $jun[$i] = $kj{ $hr[$i] } ;
    }
    return @jun ;			# 戻り値も配列
}


更に追加記事;(2008.03.01)
$do2->() の説明が不足していますか。ほかにもあるかもしれない。
これは、元スクリプトの中の以下のサブルーチンの部分を呼んでいるわけですね。
ということは、それを意識しないといけないので、ここだけで解決しないということです。

        my $do2 = sub {
                ( substr( $_, 19, 2 ) == $bbcd and substr( $_, 25, 2 ) == $rnum )
                        or next } ;



実際にテストしてみて、予想指数は偏差値でないとダメかな、と思うくらいに使いやすさを実感。
「この馬は単勝で20倍つかないとアタマで買えないな〜」などと遊ぶことも出来る。
馬連や三連複のオッズと比較する場合でも2頭3頭の馬の数値を加算して比較が可能で、条件
さえうまく設定すればオッズと連動した買い目の自動抽出も精度の高いものができそうだ。

たとえば、馬連の場合。以下。

 京都11R 5月 7日 都大路S   4歳上:OP特:1600m芝外C重15時30分発走10頭1  71混:45 [ 88] 21
予想: 1.34.23 ( 3F: 35.34 ) ⇒ レースタイム: 1.35.5 ( 3F: 36.8 )
 馬単(8→4)\7640: 馬連(4-8)\3730: 三連複(4-8-10)\4880:
 三連単(8→4→10)\39620: ワイド(4-8)\1130:(8-10)\1030:(4-10)\330:
  1| 1+ブラックカフ+ 1|   ?2| 牡6| 4武幸四郎54o変& A%東 -8|  5.2( 3).=31N-6WA2a2q 63r1N| 49[ 9]
  2| 2+マヤノシャド2  |115*7・ 牡7| 4熊沢重文54o替& A・西 -4| 20.9( 9)--7cf:/++.  | 52)8K*   [ 7]
  3| 3Bウインクリュ|  |116*8・ 牡6| 5佐藤哲三57o変! A%西 -4|  7.1( 4)<+68K:7- - -( 43)5K|   [ 5]
  4| 4Bミスティック2  |113*5: 牡5| 7川原正一54o替! A・西 +4|  3.9( 1).+86H+4W$C#=: 55r1H| 51[ 2] 150
  5| 5|スターイレブ|  |1  ?3| セ6| 3渡辺薫彦54o変! A%西 -2|  9.7? 6)<+7aK:/+C5 -( 33)5K| 24[ 8]
  6| 6Cマイネルハー|  |  5+8| 牡4| 4幸英明 55o    A・西  0| 12.8( 7).+99H+ ZC5 -q 61)5K: 34[ 4]
  7| 7+サイレントデ|  | 23+8・ 牡6| 1川田将雅57o替! A+西 -4:  7.5( 5)<+87K: - - -( 38)1K|   [ 6]
  7| 8aロードマジェ6  |  4+6| 牡4| 4上村洋行54o換! A・西 +2| 13.5? 8).+deN+ VB3b3| 53r1N: 62[ 1] 300
  8| 9|アグネススペ|  |1 3?8| 牡9| 5角田晃一52o換! A+西 -8 131.3?10).+baH+6-+. -( 38)1H- --[10]
  8|10Cトップガンジ7  |121+4: 牡4| 4秋山真一54o変! C・東-10:  4.3( 2)<+75r+ WC5 -: 58r2c| 50[ 3] 150
.
京都11R 5月 7日 by DM
  [ 1- 2]   47.2 (116.3/122.2):  [ 1- 4]   11.5 (119.4/128.5): *[ 1- 6]   35.5 (124.9/123.4):
  [ 1- 8]   42.8 (116.6/122.6): +[ 1-10]   10.4 (121.9/129.0):  [ 4- 6]   28.5 (117.3/124.4):
  [ 6-10]   28.1 (119.8/124.5):

 ↑ DM指数を単純に偏差値化して、2頭の合計値( ⇒ 分子 )が 115以上を表示。。
数値の高い有力なフォーカスには + のマーク。
オッズと比較して買い目になるものには、* のマークを付ける。

現行は、合計値は「積を平方して2倍」で求めている。

京都11R 5月 7日 by INDEX
 +[ 1- 4]   11.5 (123.9/128.5): *[ 1- 8]   42.8 (125.3/122.6): +[ 1-10]   10.4 (123.4/129.0):
 *[ 4- 8]   37.3 (126.8/123.2): +[ 4-10]    8.9 (124.9/129.7): *[ 8-10]   40.4 (126.3/122.9):

 ↑ は、sSeia の指数を偏差値化した結果。
妥当かどうかは分からないが、オッズの下限値として使っているのが、↓ 

my $log = 45 * ( 31 - log( $odds ) ) / 10 ;

つまりオッズが上がるほど、分母 が小さくなり、1 を超えれば買い目として成立すると いうわけ。
この方法で多くのサンプルをチェックすれば、予想指数の優劣が歴然とする?

分母は上記のように閾値としてオッズから算出していたが、これも票数の偏差値からに変更 した。
必ずしも同じ結果になるわけではないが、人気との乖離はコチラのほうが明快。



数値に置き換えられる予想であれば、偏差値化してから評価すれば見合ったオッズが探しやす
いということ。精度の高い予想さえあれば、原価を把握しているようなもので、やり方によっては
「商売繁盛 間違いなし。おめでとう〜」というところだが、、
ほかにも考えることはいろいろありそうだ。

しばらくこの線を追ってみたい。データ処理というより馬券の購入方法へ比重が大きくなってくる
ので、あそぶシリーズは今回で終了することにした。

偏差値のテストは、紐めがねのほうで3週間程度やる予定。データとして残したい。
馬券の方も好調で、これ以上やることといったら自慢することくらいしかない。
磨くべき原石はここにあるものだけで十分な気がする。



異動や卒業、転居などでメンバーも大分減り、逆に自力でデータを生成できる人が増えてきた。
だからといって、逆に提供してもらいたいようなデータはない。
ここのデータを求めてくるひとも、ちょうど今は誰もいない状態なのでゆっくり一休み。

ギブ&テイクの関係が希薄になったことと、目指すところに辿り着いた安堵感から、これ以上書
き続ける動機もなくなってしまった。

あそぶシリーズが終わっても、あそぶのを止めるわけでも、家に帰るわけでもない。
競馬もやるし、スクリプトも書くし、日記も書き続けるつもり。
でも、シリーズは書くことが無くなったということ。

今後に関しては、質問に関する応答で十分だと思う。半分くらいが、今までの例だと
「書いてあるのでよく読んでください」
「自分で考えてください」
「え?なるほど。考えてみるので待ちてくりくり」
「あ〜そうですか。でも、興味ないので他をあたってください」

前にもドコカで書いたけれど、聞くときは相手の方が自分より「知らない」と 考えて質問した方が
イイ。自分より知らない相手に聞くわけだから、まず質問する相手に理解させる必要がある。
そう考えれば自己解決することもある。もちろん例外も多いけど。
意味や意図がよく分からない質問は無視するのがネットの常識らしい。

というわけで、重要な質疑でもあれば、それに応じて記事を書き換える予定。
kbtk.pl のスケルトンやVB.NETでのタイマー取得については面倒臭くなったのでヤメ。

いろいろ修正するのに自発的に書き換えることもあり得るけど、原則放置ということ。

これまで書いてきたことの多くは、他人の経験と智恵とを踏み台にしたものだ。
自分のアイデアを出す必要は殆んどなかった。あるとすれば、組み合わせと応用について少し
意見を述べたに過ぎない。

特に馬券の買い方などには、仲間内だけの攻略法みたいなものがあって、いい想いを共有させ
てもらってきたが、それをスクリプトでモット楽にやろうという気持ちもあった。半分くらいは恩返
し出来たかな、というところだ。

それでもココには、競馬データで遊ぶのに必要な考え方とツールは揃っているはず。
それらを活用して、これからは自分自身のアイデアを追求する時間を作っていきたい。

指摘や質問などは、メール( or 伝言版 )で、
但し、yahooや鳩メールその他はサーバーでスパム処理しているので届かないこともある。
そのときはヒラにご容赦を、



蛇足ながら、

予想指数が能力指数とは、全く違うものだということは誰でも知っている( or 分かる )ことだけど、
個々の馬の成績を調べているうちに、いつのまにか混同しかねない。
自分はスピードINDEX( という一つの能力指数 )の正確さを求めるために、遊びながらとはいえ
ケッコウ苦労もした。自分なりの検証と蓄積と推理との殆んどをそのために費やしてきたから拘り
もある。だから、INDEXがオッズを構成する小さな一つの要素でしかないと納得するまで永い時間
がかかってしまった。バカだね。

無視できない重さであることには変わりないが、他の要素を考えたうえでなら、時には無視したほう
が面白いことだってある。

予想指数としてある程度の肉付けができたら、それを偏差値になおしてからオッズと比較検討する
のが多分正しいのだと思う。でも、最善かどうかは分からない。
現段階、自分は偏差値化する前のものを使っているが、いずれそっちにいくような気がしている。
いろいろ試してみたいこともある。
偏差値のやりかたで最近の好配当は、現行と殆んど変らずに取れているが、過去をみるとかなり落
ち込むことがあった。その辺の原因を究明しないと乗り換えは難しい。

と言いながら、ほとんど移行済みの状態で、次々といろいろな発見もある。タイムから速度への方も
ほとんど変更が終わったけれど、やることが減るどころか増えてしまった。エンドレス。

最後の項は必要に応じて補完や追加・修正用に使うことにしましょう。



10. だそく 

Perl スクリプト 
ソート&順位付けについて (2006.06.05)

Perl スクリプト  年月日場の一行データ処理 (2006.06.16)

Perl スクリプト  薄暮の時期はレースの順が、、 (2006.07.23)

Perl スクリプト 2006年分の合同ハンデ専用、説明抜きだが追加。 (2007.02.08)




INDEXへ トップページへ