ラベル シミュレータ の投稿を表示しています。 すべての投稿を表示
ラベル シミュレータ の投稿を表示しています。 すべての投稿を表示

2014年10月4日土曜日

BaseBall Simulation できました。

作り始めから半年以上経ちましたが、ようやくそれっぽいものが出来ました。

BaseBall Simulation
http://coffeespecial.web.fc2.com/baseballsimulator/index.html

ずーっとC#で頑張ってましたが、C#で作ってもさくっと使えないのが残念なので、Webで動くjavascriptで作ってみました。9回延長戦なしの試合を10000試合行って、その結果を表示します。

選手データを読み込ませる方法をどうやろうか色々考えてる最中で、今はとりあえずすべてrandomにそれなりの選手を6チーム分作ってます。各チームに平均打者と平均投手、それにダルビッシュと二軍選手を混ぜてるので、ピッチャーをダルビッシュにしたらどのぐらい点数が入らなくなるか、とかやってみると面白いかもしれません。

アルゴリズムとしては、ボールに当たる、三振する、ホームランを打つ、の各OddsRatioを打者投手で計算して、起こり易さをOddsとして求めてから確率に変換するという方法を取ってます。なので投手を平均投手にすれば、打者の元能力と同じような打率、出塁率になるようになっています。

javascriptは、以前勉強しようと思った時に、あの適当な型の扱いと呪文のような

(function(x){});

が良くわからなくて挫折していたのですが、C#っぽく静的に型をつけれて、尚且つVisualStudioの補完機能を使えるTypeScriptというjavascriptのコードをコンパイルしてくれるやつを使ってなんとかかんとか再チャレンジしました。

TypeScriptはクラス、インターフェースとかもろもろのオブジェクト指向的な記述をC#と似たような形で導入できるので、プロトタイプチェーンとはなにもんじゃ、クラスがないとは何事だ!死ね! という人にも扱いやすいんじゃないかなと思います。

実際ぼくもこれを使って、javascriptじゃないみたいにjavascriptを書いていくうちに、だんだんとjavascriptの雰囲気というか、どうやって書けば良いのかをコンパイル後のjsファイルを読んだりしてみて、手を動かしながら理解できてきた気がします。しっかりjsを使いこなすためには一度はちゃんと言語仕様について勉強しないとだめなのもたしかなのですが、そればっかり先行して、まったくやる気がでないよりは、それっぽいものを書いてそれっぽく動いてくれたほうがやる気も出る(気がする)ので、オススメです。やっぱり慣れてない言語を扱うときに、IDEの補完機能があるないは全然書くスピードが違いますね。

あと、何気でVisualStudioWebのhtmlとcssの編集も、かなーり優秀で良いです。4,5年前に初めてhtmlに触った時にこれを使いたかったなって凄い思いました。やっぱり補完機能って神。

2014年5月23日金曜日

久しぶりに

めっちゃ前に作ってた野球シミュレータの改良をやりました。

たまにはいじらないと自分で書いたコードが暗号に見えるようになりますね。すでに意味不明部分多数で手遅れ感満載ですが。

ほんとうはjavascriptかなにかweb上で動くもので作れればいろんな人に使ってもらえる可能性も増えて、いろいろと改良する点も意見としてもらえると思うのですがいかんせんC#しか使えないということと今現在新しい言語をいじくる余裕があまりないというので停滞中です。一応javascriptの本とか買ったんですけどね。ほとんど手付かず状態です。

とはいっても、C#でうまく設計さえできれば他の言語でかくのも結構楽にできるんではないかと(勝手に)予想してるので当分の目標はC#のWindowsWPFアプリケーションとして仕上げたいなぁともくろんでます。今のところ新しいやつでは

  • DHありなしの対戦
  • CSVで登録する選手を任意に決定できる
  • 先発ローテーション(最終的には抑えの登板とかも)実装
  • 天候、パークファクターの導入(まあこれは別にいいっちゃいいかな)

といった当たりをできるようにすることを目標にしてます。さっき見返してたら地味にもうこれ作り始めてから半年以上経ってるんですよねこれ。完成するのいつかな…

2014年5月8日木曜日

異なるリーグに所属する選手同士の対戦予測

今回は異なるリーグに所属する選手同士が、あるリーグで対戦した時にどの程度の成績を残すのかということを考えてみたいと思います。今まで考えていたのはおなじリーグ内部での話でしたから、最終的に少しリーグ平均のOddsでいじれば良かったのですが、投手打者そして今現在所属するリーグが異なっている場合ちょっとややこしくなります。

具体的には打者が打高のリーグに所属投手が投高のリーグに所属そして現在のリーグの反発係数が2つのリーグに比べて高いというような場合です。 ボールが飛びやすかったり、球場が狭かったりと言った平均的に打者が有利なリーグに所属している場合は、打者および投手の安打発生Oddsは高くなる傾向にあります。逆の場合も同様で、したがって異なるリーグに所属している選手同士を対戦させようとする時は、それぞれが所属するリーグの影響をまず取り除き、その上でodds ratioを考えるのが妥当でしょう。

Oddsを用いる成績予測の考えの根底には、選手の突出度をOdds同士の比であるOdds Ratioによって比較するという概念があります。この作業は、数学や物理でいうところの規格化手法です。規格化とは、ある値を基準として、自分の大きさをそれの何倍かで表すという考えです。これを考えれば、打者、投手、今考えているリーグをLb,Lp,Lthisとすると $${Odds Ratio}_b=\frac{Odds_b}{Odds_{Lb}}$$ $${Odds Ratio}_p=\frac{Odds_p}{Odds_{Lp}}$$

という風に表せます。これを掛け算することで、打者と投手を合わせた突出度を計算できます。そしてそれに今打者と投手が所属するリーグのOddsを掛け算することで、今いるリーグの平均と比べることができ、合理的にOdds Ratioを算出出来ます。 $$Odds Ratio_{AvsBonLthis}= Odds Ratio_b\cdot Odds Ratio_p\cdot Odds_{Lthis} $$

  • $Odds Ratio_{AvsVLthis}$ : AとBがリーグLで対戦した時のオッズ
  • $Odds Ratio_b$ : Batterのオッズ比、リーグでの卓越度
  • $Odds Ratio_p$ : Pitcherのオッズ比、リーグでの卓越度
  • $Odds_{Lthis}$ : PitcherとBatterが所属するリーグのオッズ

ex).平均打率0.300のリーグで0.350打つバッターと平均打率0.270のリーグで被打率0.280のピッチャーが超低反発球が導入された平均打率0.220のリーグに所属する場合の期待される打率 $$ \begin{aligned} Odds Ratio_{Lthis} &=\frac{0.350/(1-0.350)}{0.30/(1-0.30)}\cdot \frac{0.28/1-0/28)}{0.27/1-0.27}\cdot 0.220/(1-0.220)\\ &= 0.372\\ &\therefore P = \frac{0.372}{1-0.372} = 0.271 \end{aligned} $$

しかしこの考え方にも欠点があります。それは、比べるリーグのレベルが明らかに異なる場合です。

例えば少年野球チームで平均以上にヒットを打つバッターと、プロ野球選手だけど1軍ではボコボコに打たれまくった投手が対戦するときなどにはこの方法を用いてはいけません。Oddsの考え方の基礎にあるのは、その選手が平均値からどれだけ突出した選手なのか、ということに焦点を合わせて結果を推定するというものです。

そのため、比べる2選手の所属するリーグの選手の能力が基本的にはほとんどおなじであるということが大前提となっています。したがって、同一のリーグでも大きく年代が異なる選手同士の対戦成績予測や、NBPとMLBといった明らかに能力の平均値が異なるリーグの選手同士の成績予測にはこの方法を用いるのは適切ではありません。

2014年5月7日水曜日

複数の可能性がある確率でのOddsRatioの使い方

前回に引き続いて、OddsRatioのお話

OddsRatioが勝率の違うチーム同士の対戦成績や、ある打者と投手が対戦した時の打率や奪三振がどの程度の確率で起こるのかを計算する際にとても有効であることについて書きました。

今回考えて見たいのは、確率の分岐先が複数存在する場合です。

2014年5月6日火曜日

野球シミューレーションを作る時に大事なこと

FanGraph今月のまとめ!みたいな記事に乗ってた、シミュレータを作る上で学んだ10のこととかいう最近ネットでありがちなタイトルの記事がなかなかおもしろいことを書いてあったので、ちょっとメモ

2014年4月18日金曜日

野球における打率とサイコロ

去年あたりから、プログラムの練習を兼ねて野球のシミュレータを作っています。
その時改めて野球の結果と偶然とか確率と言ったことについて考えた時に、ふと疑問に思ったことがいくつかあったので、この間Twitterでどばどばと適当に垂れ流した内容をもとにちょっと考えを練りなおしてみました。

1.打者の結果はサイコロとおなじなのか?


例えば出塁率.400のバッターが居たとして、そのバッターが10打席回ってきた時にヒットを打つ本数と、仮に10面あるサイコロが合ったとして(このような過程は乱数を用いれば作ることが可能です)、そのサイコロのうち1~4の面が出れば出塁とする場合とで厳密に言うとヒットの出方が違うのではないか、と言う疑問です。

ちょっとややこしいのですが、野球における打率や出塁率などの率系の指標はあくまで得られた平均値でしかなく、平均的にサイコロとおなじ割合でヒットが出るとしても、そのばらつきまでもおなじであるとするのには、大雑把には近似できるとしても厳密には異なるのではないかということです。
サイコロであれば、その時の出塁の数は二項分布で表現できます。一方現実の野球選手の出塁が決まる過程は、ピッチャーが投げた球がストライクになるかどうかとか、打った球がどこに飛んで行くかとか言ったもっと上位の過程の結果として表されるので、最も確率が高いのはサイコロで表した際の最尤値と一致するとしても、そのまわりの値を取る確率が先の二項分布で表される確率とくらべて高い、もしくは低い可能性は捨て切れません。


図1:N=50,p=0.30の二項分布(青色)と予想した現実の分布の違いのイメージ図。縦軸は確率。

とまあそんなことを考えていたんですが、いろいろと考えた結果これは間違いであるという結論に至りました。結論をいうと

もし図のような確率分布となるとすれば、おなじヒットを打つ能力を持つ打者が二人板として、序盤の打席でたまたまヒットを多く打った選手はもう一人の選手と比べて、その後ヒットを打つ能力が下がる必要がある。ということです。

普通に考えて、おなじ能力の選手が二人いればその二人が現在立っている打席でヒットを打つ確率は全く同じであると考えられます。したがって1打席だけの結果に注目するとその確立はベルヌーイ試行として表すことが出来ます。ベルヌーイ過程とは、コインを一枚投げた時に表が出ると1,裏が出ると0とみなす実験を行うことを意味します。そしてこのベルヌーイ過程がN回行われた時、出た表の数の合計を確率として表すと二項分布となることは証明されています。したがってこれを逆に考えれば、結果が二項分布とならない過程では、一回一回の打席の結果はベルヌーイ過程ではない他の過程によって決定されている事になります。

これは、過程が行われている時にバッターの持つ平均的な出塁割合 :p の値が変わらないということに矛盾するため、打席が増えるに連れて、過去の打席の結果により現在の打席のヒットを打つ能力が上がる、もしくは下がる事となり、これは直感に反します。
(ヒットを打ったからと言って次の打席は打てないだろうというのは、パチンコで負けたからと言って次の日勝てる確率が上がるわけではないことと同じですね)

ちょっとややこしいのは、この議論では、打者が仮に確定された真の実力pの確率でヒットを打てる、ということを仮定していますが、このpの値は必ずしも打率の値ではない(かもしれない)ということです。

ココらへんはベイズの定理が関連するので、どこまで考えるんぞという話であるうえに私自身しっかり理解できていない可能性が高いので微妙ではあるのですが、プロ野球の打者が持つと期待される打率の値は(恐らく)ある値p'を平均とした正規分布のような確率密度関数で表示できるとします。
次に今シーズンである打率pを残した選手が居たとして、その選手が持つであろう実力の打率qを推定することを考えます。

実際の打席に立つと、実際の過程をへることによるぶれが生じてしまうので、pからのずれが生じます。

これは表と裏が出る確率が1/2,1/2のコインを4回振っても毎回2枚が表になるとは限らないことと同じです。

普通に考えると真の打率はpであるとすればよい様に思うかもしれませんが、例えばpが極端な値.500をとった時のことを考えてみます。これは特に打数の少ない選手で起こりがちですが、たまたま数打席ヒットが多く出たからといって、その選手がイチローを超える打率を真の実力として持っているとは考えれない、せいぜい.300ぐらいであろうとかんがえると思います(普通は)。この作業が先のベイズの定理に当たる部分です。

ほとんどの選手は.250~.280ぐらいの間に真の実力があるとかんがえられますから、そもそも.500の実力を持つ選手は殆どいません。したがって、.500をシーズンの記録として残した選手のほとんどは.250~.280の平凡な実力を持った選手がたまたま運良くヒットが多く出た、と考えられます。これを数学的に調べようと思うと、選手がある真の実力を取る確率に、その実力を持ってシーズンを過ごした際に打率.500を取る確率を掛け算することで調べることが出来ます。これがベイズ的な打率へのアプローチです。

したがってシミュレータを作る際も、来シーズンの予想をするシミュレータをつくろうとするならば、このベイズから推定されたXを用いる方が信頼度が上がるのではないかと考えられます。

とはいえそのような処理をすると、例えば.350で首位打者を取ったようなバッターは「たまたま今シーズンは実力以上のちからが発揮されただけで、本当の実力は平均にもっと近い値に違いない」と推定されて平均へと回帰する圧力がかかりますから、全員の能力が平均化されシーズン予測の値も全チーム似たような得点となる可能性があるので、エクストリームな値が得られない分インパクトとしては小さいものになってしまうかもしれません。

2013年10月28日月曜日

シミュレーター(コンソール版)



この間のWindowsForm版の奴はあまりにも計算速度が遅いし、自分のコードがわけわからなくなったので(こっちがメインの理由)もっかい下地から作りなおして

・リーグ、チーム、プレイヤーの数を自由にユーザーが作成可能
・1チームだけだと試合と言えないので2チームで試合を可能
・誰が出塁しているのかを保存してランナーの個性をつける
・試合結果を年度ごとに保存してそのサマリーを書き出せる
・シミュレータのベースとなってるのはBattingRunsという考え方なのですが、その係数をいじっていろいろな条件でシミュレータを動かす
・一軍登録、二軍登録を作る

という機能を加えてみました。コンソールだけど。
その結果クラスがめちゃくちゃ大量に発生してしまって管理が大変です…
オブジェクト指向の設計の方法とかいう本をちょいちょい読みながら作ってるんですが、クラスの量が大量になってくるとオブジェクト指向の良さが生きてくる感じがします。
最初の頃に比べてだいぶC#の用語(メソッドとかプロパティとか)の意味もだいぶつかめてきました。C#の技術本読んだだけで理解したつもりになってたのが作ってる途中でどんどんわかってきて、前自分が書いたコードが汚くみえて書き直すことばっかりです。なんかこうやっていろいろわかっていくのが実感できるのは楽しいです。
これからオブジェクト指向も勉強しないといけないですね。

2013年10月21日月曜日

C#で打線シミュレーターを作る

前にシミュレーターを作りかけで投げ出してたんですが、今度はWindowを出して普通のソフトっぽく動かせるようなやつを作ってみようかなと思いたって、ここ2日ぐらいこないだ作ってたコンソールアプリを流用しながら、Windowsフォームを使って(ようするに普通のソフトみたいな外観で)ユーザーがスタメンの選手とか選手の成績とかの設定をいじって、その時の打線の様子をシミュレートできるもんを作ってました。

スクリーンショットはこんな感じ。なんか適当に配置していたらやたらと横長になってしまいました



元々のシミュレーターは、プログラムの中身に誰をスタメンにするのかとかその選手がどのぐらい打てるのかっていう情報を埋め込まないといけないちょっと不便なものだったので追加の機能として

・今読み込まれている選手データを表示してその成績を表示する
・ユーザーが新しい選手データを登録できる
・スターティングメンバーを選手データから選択して配置する
・シミュレーター本体の処理がめっちゃ重いので、今どのぐらい処理が終わっているかを見れるようにする

をできるようにしました。
といっても、読み込むデータに制限が多すぎたりちょっと不便なことも多いので改良しなくちゃいけないことも多いので、もうちょっと柔軟性をもたせたプログラムに変更していかないと、っていう状態です。

それにまだ外部からCSVで選手データを読み込んだり、シミュレーターを動かした結果を保存したりとか、結果をグラフでわかりやすく(できればかっこよく)表示する、みたいな基本的な機能もできていないので当分はそれを実装するのを目標にちょいちょい改良できればなぁと思ってます。