9. テキストデータの集計・検索
kbsTk や sskj で出馬表や成績ファイルを出力しているうちに、データがたまってくる。
これらのデータを、自分の求める条件で集計・検索する方法を知らなければ、
ただのゴミ
でしかない。
これらは、整形されたテキストファイルで固定長なので位置を決めてから順番に処理する。
固定長ではない部分もそれなりに処理すればOKで、殆ど問題にはならないはず。
一方、カンマなどで区切られた csv ファイルでは位置は関係なく順番だけで処理できる。
固定長の場合は、そのままでも自然に見ることが出来る(まぁ、JV ファイルは見づらい?)
が、csv では EXCEL など他のツールが必要になることもある。
固定長のまま、schema.ini をつかう方法もあるが、アッサリ、csv にコンバート
してやれば
いいだけの話でここで問題が生じるとは思えない。
好きなほうを使えばいいだけ。但し、ここでは固定長中心。
** sskj.pl は削除したままなので近いうち再UP予定(内容の変更はなし)。
-----------------------------------------------------------------
ここでは、Perl で kbsTk データの処理について少し、、
New に対応させていますが、旧 kbsTk のでも少しの書き換えで大丈夫。
集計・検索の処理の流れとしては
1. 対象ファイルの指定。( どのファイルか分からなければ処理のしようがなひ )
2. ファイル内の単位、例えば1行一単位とか、その行の中のドコにナニがあるのか知る。
3. 出力したいのは、ナンなのか自問。( 要するに、自分の知りたいことよ )
4. スクリプトを書く。( 最初はヒトの作ったものを参考にして改良するのが正しい )
5. 結果を出力して思索。( 利益の出そうなデータなら独占し、そうでなければ公開? )
6. 儲かったら自慢し、見損じだったら次の集計・検索に向かう。
-----------------------------------------------------------------
基本的には他のスクリプトでも、なんども繰り返し使っている方法ですが動くものなら
何度でも使う。
上記の 3. 以降は、人それぞれなので 1. 2. について説明します。
対象ファイルがタクサンあるフォルダで、下のスクリプトを(スクリプト名は自由に)実行
すると、同じ場所に syuk_DD.dat(ダート) と syuk_TT.dat(芝)に分類されたファイルが
出来ます。
ただそれだけのことです。
もっと細かい分類が必要なら、書き換えるべし。
#!/usr/bin/perl
#===========================================================================#
# 対象ファイル(例)
# ファイル名のアタマ2桁が 20 から始まる3桁以上の数字( ^20\d+ )など
# これで2005xxxxout.dat などが全部引っ掛かる。同じフォルダには、紛らわしいのは
# 置かないこと。あるいは、もっと厳密に縛ることも可能。
use strict;
my $flg = 0 ;
my $outD = 'syuk_DD.dat' ; open OUD, ">$outD" ; # 出力用ファイルを開く
my $outT = 'syuk_TT.dat' ; open OUT, ">$outT" ; # 出力用ファイルを開く
print STDERR " ファイルリスト作成中 \n";
my @t_files = grep { -T } glob "*" ; # 100個あれば100個
for ( @t_files ) {
my ( $list ) = (split '/', $_)[-1];
unless ( $list =~ /^20\d+/ ) { # ファイル名を抽出、要らないのは外す
print STDERR " 対象ファイルではないので Skip! $list \n" ;
next;
}
open INF, $list ;
while ( <INF> ) {
if( /^.{6,7}R/ ) {
$flg = /0m ダ/ ? 1 : 2 ; # タイトル行から芝・ダートを分類
next ;
}
next unless /^\s+\d\|/ ; # 行頭が数値と | ならOK
# 旧Ver. なら /^\d\(/ ★
next unless substr( $_, 62, 2 ) > 0 ; # 人気順位が入っている位置
# ↑ 違っていたら修正。行頭は 0 から数え 、62文字目から2文字の意
print OUD if $flg == 1; # ダート
print OUT if $flg == 2; # 芝のとき
}
close INF ;
}
close OUT ; close OUD ;
これで、第一段階はクリアとします。
-----------------------------------------------------------------
次は少し長いです。長いだけで仕掛けは簡単ですが、、
スクリプト名を適当に付けて同じフォルダで実行すると、out_DD.dat 又は out_TT.dat
が出現します。
芝orダートを指定します。ダートなら 1、芝なら 2 です。
抽出条件は、自分で指定します。いくつか例があるので、試してください。
考えればワカルッチャ。簡単すぎて、小学生でも出来ます。
全部 # でコメントアウトした場合は、全データが出ます。
出力ファイルの最後尾に集計データが表示されます。
出力フォーマットは、いつもここで使っているもので詳細はスクリプトを
参照してください。
改変は勝手にやってください。お好きなように、、
下記の例と、変数などの位置が異なる場合はそれぞれ調整してください。未確認です。
#!/usr/bin/perl
#===========================================================================#
# 全面修正
use strict ;
######### ダートなら 1 ##### 芝なら 2 ###############
my $fflg = 1 ; # ★
my $inF ;
my $outF ;
if ( $fflg == 1 ) { $inF = 'syuk_DD.dat' ; $outF = 'out_DD.dat' ; }
elsif ( $fflg == 2 ) { $inF = 'syuk_TT.dat' ; $outF = 'out_TT.dat' ; }
else { exit() ; }
open INF, $inF ;
open OUT, ">$outF" ;
my ( $a1, $a2, $a3, $a0, $maxb, $maxd ) = () ;
my ( $c1, $c2, $c3, $c0, $b1, $d1 ) = () ;
my $fuka = 0 ;
my $fukb = 0 ;
my @chk_a ;
my @chk_k ;
my @chk_n ;
my $head = $fflg == 1 ? 'ダ' : '芝' ;
while ( <INF> ) {
next unless( /^\s+\d[\|\(]/ ) ;
# 6|11|ゴールデンロ 4牡8| 4赤木高太57o -1 & C・西 0z215.7(16) -94- +-- -( 77) -[16]
# 6|12aアドマイヤマ 43牡6|13武豊 57o 241- ・&*4・西-16v 10.7( 3)c -4c: VBc q( 86)3 [ 3] 250
# 7|13aサイレントウ8 6セ6| 7コーツィ57o ・&*4・外 +8: 2.0! 1)b +53: -A8 *( )1-[ 1] 120
# $u_ban $ksp $kwr$mae $toz $tj $chaku$fukh
# $posi $ysm $pa$pi$pu$pe $idx
# $yuw
# $tjyu $mkz$mkall$mkzen
#
my %mrk_a = ( 'a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15,
'g' => 16, 'h' => 17, 'i' => 18, ' ' => 20 , '-' => 20 ) ;
my ( $u_ban, $kaku, $dash, $sasi, $posi, $sinba, $ksp, $kwr, $mae, $ysm, $yuw,
$tjyu, $bnmk, $toz, $tj, $pa, $pi, $pu, $pe, $po, $mkz, $mkall,
$mkzen, $idx, $chaku, $fukh ) =
unpack '@4 A2 @6 A1 @19 a1 @20 a1 @21 a1 @25 A1 @26 A2 @44 a2 @46 a1 @47 a2 @49 A1
@52 A3 @55 A1 @56 A5 @62 A2 @67 a1 @68 a1 @69 a1 @70 a1 @71 a1 @73 a1 @74 a2
@76 a2 @79 A3 @86 A2 @89 a4', $_ ;
my $pinum = $pi =~ /[1-9]/ ? $pi : $mrk_a{$pi} ;
my $punum = $pu =~ /[1-9]/ ? $pu : $mrk_a{$pu} ;
my $omk = substr( $_, 63, 1 ) ;
############★ 抽出 条件 は 以下で指定 ★###################
# next unless $pe eq '-' ;
# next unless $dash >= 7 ;
# next unless $tj > 2 ;
# next unless $mkzen =~ /q$/ ;
# next unless /武豊/ ;
###
###------------------------------------------------------------
##### カウント ##### 異常のところでは中止のみ加算
if( $kwr =~ /替|変|代|換/ ) { # 乗り代わり
if( $chaku == 1 ) { # 一着のとき
$a1++ ; $b1 += $toz ; $maxb = $toz if $maxb < $toz ;
push @chk_n, $toz ; push @chk_a, $toz ;
$fuka += $fukh ;
}
if( $chaku == 2 ) { $a2++ ; $fuka += $fukh ; }
if( $chaku == 3 ) { $a3++ ; $fuka += $fukh if $fukh ; }
if( $chaku > 3 ) { $a0++ ; } # 着外
if( $chaku == 0 ) { $a0++ if /中止$/ ; } # 異常
} else {
if( $chaku == 1 ) {
$c1++ ; $d1 += $toz ; $maxd = $toz if $maxd < $toz ;
push @chk_k, $toz ; push @chk_a, $toz ;
$fukb += $fukh ;
}
if( $chaku == 2 ) { $c2++ ; $fukb += $fukh ; }
if( $chaku == 3 ) { $c3++ ; $fukb += $fukh if $fukh ; }
if( $chaku > 3 ) { $c0++ ; } # 着外
if( $chaku == 0 ) { $c0++ if /中止$/ ; } # 異常
}
print OUT ; # 1行づつ出力。必要なければコメントアウト
}
my $k_a = $a1 + $a2 + $a3 + $a0 ; # レース数・乗替
my $l_a = $c1 + $c2 + $c3 + $c0 ; # レース数・継続
my $e1 = $c1 + $a1 ; # 1着数合計
my $e2 = $c2 + $a2 ; # 2着数合計
my $e3 = $c3 + $a3 ; # 3着数合計
my $m_a = $l_a + $k_a ; # 対象の全レース数
my $f1 = $d1 + $b1 ; # 単オッズ合計
my $k_r = $a1 + $a2 ; # 連対数合計
my $l_r = $c1 + $c2 ;
my $k_f = $k_r + $a3 ; # 3着入着数合計
my $l_f = $l_r + $c3 ;
my $k_1 = 100 * $a1 / $k_a if $k_a > 0 ; # 単率
my $l_1 = 100 * $c1 / $l_a if $l_a > 0 ; # 単率
my $m_1 = 100 * $e1 / $m_a if $m_a > 0 ;
my $k_2 = 100 * $k_r / $k_a if $k_a > 0 ; # 連率
my $l_2 = 100 * $l_r / $l_a if $l_a > 0 ; # 連率
my $m_2 = 100 * ($k_r + $l_r) / $m_a if $m_a > 0 ;
my $k_3 = 100 * $k_f / $k_a if $k_a > 0 ; # 複率
my $l_3 = 100 * $l_f / $l_a if $l_a > 0 ; # 複率
my $m_3 = 100 * ($k_f + $l_f) / $m_a if $m_a > 0 ;
my $b2_ = $b1 / $a1 if $a1 > 0 ; # 単配平均
my $d2_ = $d1 / $c1 if $c1 > 0 ;
my $f2_ = $f1 / $e1 if $e1 > 0 ;
my $f2 = &chuo_t( @chk_a ) ; # 単配中央値
my $d2 = &chuo_t( @chk_k ) ;
my $b2 = &chuo_t( @chk_n ) ;
my $f3d = 100 * $f1 / $m_a if $m_a > 0 ; # 単回収
my $d3d = 100 * $d1 / $l_a if $l_a > 0 ; # 単回収
my $b3d = 100 * $b1 / $k_a if $k_a > 0 ; # 単回収
my $fukc = $fuka + $fukb ;
my $fk1 = $fukc / $m_a if $m_a > 0 ;
my $fk2 = $fukb / $l_a if $l_a > 0 ;
my $fk3 = $fuka / $k_a if $k_a > 0 ;
my $mkA = &admk( $f3d, $fk1 ) ;
my $mkB = &admk( $d3d, $fk2 ) ;
my $mkC = &admk( $b3d, $fk3 ) ;
if( $m_a and $l_a and $k_a ) {
printf OUT
"%s@%4dA%4dB%4d全%5d:単%5.1f 連%5.1f 複%5.1f|単%5.1f 複%5.1f%s%7.1f\(%4.1f\@%5.1f\)\n",
$head, $e1, $e2, $e3, $m_a, $m_1, $m_2, $m_3, $f3d, $fk1, $mkA, $f1, $f2, $f2_ ;
}
if( $l_a ) {
printf OUT
"続@%4dA%4dB%4d全%5d:単%5.1f 連%5.1f 複%5.1f|単%5.1f 複%5.1f%s%7.1f\(%4.1f\@%5.1f\)%5.1f\n",
$c1, $c2, $c3, $l_a, $l_1, $l_2, $l_3, $d3d, $fk2, $mkB, $d1, $d2, $d2_, $maxd ;
}
if( $k_a ) {
printf OUT
"※@%4dA%4dB%4d全%5d:単%5.1f 連%5.1f 複%5.1f|単%5.1f 複%5.1f%s%7.1f\(%4.1f\@%5.1f\)%5.1f\n",
$a1, $a2, $a3, $k_a, $k_1, $k_2, $k_3, $b3d, $fk3, $mkC, $b1, $b2, $b2_, $maxb ;
}
close OUT ;
close INF ;
sub chuo_t { # 中央値を抽出
my @sorted = sort { $b <=> $a; } @_ ;
my $aa = @sorted / 2 ;
my $ans = $sorted[$aa] ;
return $ans ;
}
sub admk {
my ( $tt, $ff ) = @_ ;
my $ans = ':' ;
if ( $ff > 120 ) {
if ( $tt > 100 ) {
$ans = '$' ;
} else {
$ans = 'F' ;
}
} elsif ( $ff > 100 ) {
if ( $tt > 120 ) {
$ans = '$' ;
} elsif ( $tt > 100 ) {
$ans = 'S' ;
} else {
$ans = 'f' ;
}
} elsif ( $ff > 85 ) {
if ( $tt > 100 ) {
$ans = 's' ;
} elsif ( $tt + $ff > 180 ) {
$ans = 'n' ;
}
} elsif ( $ff < 50 ) {
$ans = 'X' ;
} elsif ( $ff < 65 ) {
$ans = 'x' ;
} elsif ( $tt + $ff > 180 ) {
$ans = 'n' ;
}
return $ans ;
}
これを書き換えることで、成績ファイルにも応用できる筈なので、挑戦してみてください。
使いこなせれば、Perl が好きになるかも、