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年8月30日土曜日

中日広島18回戦 盛大なるネタ試合

今日の試合はとんでもなく凄い試合でした.
間違いなくシーズンでもまれに見るネタ試合です.

1 2 3 4 5 6 7 8 9 10 11
広島 0 2 0 0 0 0 0 0 0 1 3 6 9 1
中日 0 0 0 0 0 0 1 1 0 1 2 5 14 1

戦評 8月29日(金)中日 vs. 広島 18回戦

広島が熱戦を制した。広島は2-2で迎えた延長10回表、松山の適時打で勝ち越す。直後に同点とされるも11回、田中の適時打などで3点を挙げ、勝ち越しに成功した。5番手で登板したミコライオが今季初勝利。敗れた中日は、終盤に粘りを見せるもあと一歩及ばなかった。
http://baseball.yahoo.co.jp/npb/game/2014082902/top

ぱっと見平凡なただの延長戦ですが内容がすさまじい

まず皮切りは7回裏の小笠原のタイムリー.思い出してますね.

その後の赤松の守備もまたすごい.

赤松はその後得点にはつながらなかったものの9回に連続盗塁も決めてます.
流石守備走塁でプロやってるだけあるな(失礼).

そしてあれよあれよと9回になり,同点で登板したのは防御率5点間近の中崎.そしてルナ森野に連続ヒットを許しノーアウト12塁の大ピンチ. 僕は完全に負けを覚悟してこの時点で見るのをやめました.しかしこの後謎の神ピッチを見せて0点に抑えました.いーやよくやったよ中崎期待してなくてごめんね.

お次は10回表,代打の天谷がスリーベースをうち,その後タイムリーが出て1点.こうなれば今年安定感抜群のミコライオが締めて終わりとおもいきや,まさかの失点で同点に.

更に11回,丸梵のヒットでワンアウト13塁のチャンスを作ると,代打赤松が広島お家芸スクイズ. がしかしピッチャー正面に転がり3塁ランナー丸は余裕でアウトのタイミングで万事休す,かとおもいきや何故かピッチャー小川が焦ったのか近距離で谷繁にトスして谷繁は取れず,オールセーフでノーアウトランナー2,3塁に.続く田中もスクイズの構えでまたしても焦ったかパスボール.赤松は3塁まで到達.結果として何もせず2点を取りました.どことなく一昨年の松山の悲劇を彷彿とさせます.

このあとしれっと田中がタイムリーを放ち一挙3点.

こうなるともう余裕だろ,となるところでカープの抑えは永川.

そんでこの永川が藤井にランナー一塁から今日2本目のホームランを浴びて1点差.しかしその後はなんとか踏ん張りカープが辛勝し,2点取られた永川にセーブがつき,セーブ失敗したミコライオに勝ちがつきました.頑張った大瀬良くん可哀想…

ありとあらゆるネタを詰め込んだような試合で,今日の観に行ってた人は相当面白かったと思います,気が気じゃないでしょうが.

2014年7月18日金曜日

Point Distributionから見る今年の広島東洋カープ

総得点から勝率予想をすることは,セイバーメトリクスの世界では良く行われていることではあります.有名なところでは,ピタゴラス勝率と呼ばれているもので,得点数$a$,失点数$b$とした時に,チームの勝率Pが $$P=\frac{a}{\sqrt{a^2+b^2}}$$ であたえられるというものです.こんな簡単な式ですが案外うまくフィッティングするのでよく用いられているのですが,理論的な考察としてなぜこの式が有効なのかという議論をしているものはあまり見たことがありません.おそらく,野球の得点が入るという現象がrandomの結果として考察しづらいことが要因ではないかと考えています.
野球において得点が入る,とはどういうことかを考えてみます.当たり前ですが,点が入るということは3アウトになるまでにランナーが本塁まで進塁するというふうに考えることが出来ます.なので,ヒットが3本続いたとしても点が入らない場合もある一方で,本塁打が出れば確実に点が入り,また安打が一つの回に固まると,本塁打以上の大量得点が得られます.なので,打撃結果と得点が単純な比例ではありません.
実際,サッカーの得点や野球の一試合あたりの本塁打数の分布はポアソン分布に従いますが,野球の得点はポアソン分布よりも,高得点側の確率が高い分布になってる気がします.

Point Distribution (@2013 横浜ベイスターズ)

2013年カープの得点分布でも,ポアソン分布のピークがなだらかになり,高得点側に推移したような形となっています.他のチームに関してもまあ概ねこのような分布になっているので,得点がポアソン分布に従うということを仮定するのはマズイかなといえると思います.

で,やりたいのは今年去年よりだいぶ健闘しているカープの得点分布が去年と比べてどうなっているのか見てみましょうということです.結果は以下の様な感じ
Point Distribution(@広島東洋カープ 2012~2014)
縦軸は得点確率,横軸は得点数

去年と比べて低得点の割合が減少していることがわかります.まあそもそも平均得点が3.8→4.3になってるので右に寄ることは当たり前なのですが,得点分布自体が全体通して均一になっています.やっぱり今年奮起してるエルドレッドの長打(本塁打)のお陰で,得点が安定して取れるようになっているからなのかはたまた別の理由からなのか.失点分布はそれほど変わってない様子なので,安定して4,5点取るっていうのは勝率アップにつながるのかも.

チームの長打率とか出塁率とかとリンクさせて分布傾向を出したりすると,同じ平均得点のチームでも,強い弱いの評価が出来て面白そうっすね.

ちなみに巨人はこんな感じ どっかで今年の巨人はOPS.750~.800の打者ばかりで圧倒的に打てる打者がいないというのを見ましたが,そのせいで高得点側の確率が上がって,6,7点あたりの確率が低い事につながってるのかも.

2014年7月17日木曜日

数列の収束における有界単調数列の使い方

$$ a_{n+1}>a_n, a_n>1 \Rightarrow {a_n} は下に有界な単調数列 $$

定理:有界単調数列は収束する 単調増加で,上に有界な数列${a_n}$が集合$A=\left\{a_1,a_2,......\right\} $の上限$\alpha$に収束することを示せば良い. $\forall\varepsilon>0$に対して$\alpha-\varepsilon$は$A$の上界ではない. $${n>N_0 \Rightarrow \alpha-\varepsilon<{a_n}<\alphaなるn_0が存在する}$$ このとき $$|a_n-\alpha|<\varepsilon$$ であるから,a_n$rightarrow\alpha$が示された.

2014年5月29日木曜日

C#でWebからデータを取ってくる

C#でwebからデータを取ってくるってことはあまり考えたことがなかったのですが、ちょっとプロ野球の得点分布を知りたいなと思った時に、いちいちデータを手打ちで集めるのも面倒だから自動化出来ないかなぁと考えて色々さがしてみたところ、C#でもhtmlのDOMを自在に操れるHtmlAgilityPackなるものがあるらしいのでちょっとテスト。

使い方としてはまず using System.Net でネットワーク関連のusingをもって来ておいて、HttpWebRequestとHttpWebResponseでデータを読み込みます。この時にもっと単純に取ってくるWebClientというクラスもあるのですが、それよりもrequestとresponseでストリーミングで読み込んだほうがUI(フォーム表示用)スレッドと読み込みスレッドを分離できるので、読み込み時にフォームが固まることを防げるのでよいらしいです。

WebClientよりHttpWebRequestを使った方がいい理由
http://d.hatena.ne.jp/kabakiyo/20120224/1330066622

あとはその読み込んだstringをHtmlAgilityPackにほり込んで、SelectNodesでjQuery的に検索してやれば勝手にほしいとこだけを検索して出してくれるという流れです。とってもシンプルでいいですね。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;

namespace web
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        string baseurl = "http://baseball.yahoo.co.jp/npb/game/";

        private void button1_Click(object sender, EventArgs e)
        {
            DateTime dt_now = DateTime.Now;
            string date = dt_now.ToShortDateString().Replace("/", "");

            // 今日の試合を読み込むためにurlを加工
            string url = baseurl + date + "01" + "/stats";
            //ex).url = http://baseball.yahoo.co.jp/npb/game/2014052801/stats

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "GET";
            HttpWebResponse res = (HttpWebResponse)req.GetResponse();
            Stream s = res.GetResponseStream();
            StreamReader sr = new StreamReader(s);
            string context = sr.ReadToEnd();
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(context);

            HtmlAgilityPack.HtmlNodeCollection _nodes = doc.DocumentNode.SelectNodes("/html[1]/body[1]/table[1]/tr");
            if (_nodes == null)
                break;
            foreach (var node in _nodes)
            {
                textBox1.Text += node.InnerText + "\r\n";
            }
        }
    }
}

2014年5月23日金曜日

久しぶりに

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

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

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

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

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

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

2014年5月21日水曜日

セイバーメトリクスな数字

打率、ホームラン、打点、勝ち星、得点圏打率というよく見る数字に比べて、出塁率や長打率、あるいはOPS(ここらへんは割りと浸透してるのかな?),XR,Fip,Dip,IsoD,IsoP,LOB%……とかいったセイバーメトリクス的な数字は市民権をまだまだ得れていない感じがあります。人によってはセイバーメトリクスの数字は実際の試合を見ていない数学オタクがでっち上げたもんでそんなのには意味が無いとかいう人もいたり。

じゃあそもそも、打率ってそんなに自然な数字なの?という話がでてきます。何気なく使っている打率ですが、あれの計算方法も全ての安打を無差別に足し算するという作業をしていますから、当然恣意的な指標です。しかもフォアボールはカウントされませんから、フォアボールを選ぶことは打率を上げると言う観点からいうと全く無意味です。ですから打率だけで打者の能力を図ろうとするときには、そういった消えた要素があることを考えていないと、間違った結論を導く可能性があります。

たとえば、ノースリーから毎回打ちに行ってフォアボールは選ばないし打っても毎回単打の3割バッターと、打てばほとんどホームラン、フォアボールも選びまくる3割バッター、この二人が同じになってしまうのが打率です。ここまで酷いことは無いと思いますが、そのような可能性があることは頭の何処かに考えて置く必要があります。

打点とか勝ち星とかいったものに関してはもっと不条理で、ヒットは打つものの毎回運悪くランナー無しで回ってくる弱小チームの四番よりも、周りが打ちまくるせいで毎回ランナーがいる状態で回ってくる打者の方が明らかに有利ですし、勝ち星なんてのは自分が打たれまくっても打線がバカバカ打てば増えるし、去年のいつかのDeNAの高崎投手みたいに、自責点0失点2で尚且つ自分がヒットを打って1点とって8回まで投げたとしても打線が打てずに負けてしまえば負けになるというある意味論理的でない無茶苦茶な数字です。

このように、指標の妥当性という面からセイバーメトリクスな数字を批判するのは無理があります。結局は、打率とOPSなにがちがうのかっていうのは、見慣れているのかそうではないのか、ただその違いに尽きると思います。

例えば今一般によく用いられる指標としてセーブとかHP(ホールドポイント)がありますが、あれはつい最近まで日本球界には存在しませんでした。しかし先発完投型の試合構成であったのが、先発→中継ぎ→抑えという分業制へと移行していく段階で、途中で登板する投手の地位向上が図られ、中継ぎを評価する指標として導入されたのがセーブといった概念です。では、セーブが無い時代の抑えで活躍した選手に価値がないかというとそんなことは無いですよね。今の時代の人と同じようにチームの勝利に貢献しているはずですから、同じように評価されるべきです。しかし、その選手がいた当時にはそんな概念がありませんから、おそらくは先発投手に比べてかなり選手としての価値が低いとみなされていたでしょう。

このセーブやホールドポイントと同じように、今一般に普及している指標だけが万能で十分である、とは必ずしも言い切れないはずです。そのためいろいろな側面から選手を見てやる方法として、セイバーメトリクスがあるんだと思っています。打者指標のIsoDを見れば、どれだけフォアボールを選ぶ傾向があるバッターであるかが、投手指標の一つであるFipを見れば、守備の影響から独立してどの程度その投手が抑えることが出来るのかといったことをある程度客観的に判断できます。

従来指標が絶対だ!という立場を頑なに守ろうとすると、結果として現実を見ることができなくなる恐ろしさがあります。

この記事は http://www.fangraphs.com/blogs/a-response-to-bob-ryan/を読んで思ったことをつらつら書いた(というか多分に影響を受けてい書いた)のですが、あらためて物事を認知する難しさや主観の危うさを感じれた気がします。

さきほどの内容も、セイバーメトリクスの指標を使う時にそれが絶対だという立場にたてば結局おなじことになるわけで、そこは常に注意して行かないといけないところです。

I think telling an accurate story is more important than telling a comfortable one, and the reality is that the numbers that are commonly used generate stories that are factually incorrect. ........
We’re not replacing the “Holy Trinity” of baseball statistics because we can’t enjoy the game. We’re pointing out that these statistics breed false narratives, and we value the truth.
A Response to Bob Ryan http://www.fangraphs.com/blogs/a-response-to-bob-ryan/