本日のPython mini hack-a-thon #55で作ったネタです。
今日で #pyhack が55回目とのことで、55といえば我らが誇る強打者GodzillaことHideki Matsuiやろ!
って事でRETROSHEETから松井秀喜さんの打撃データを抽出し、グラフで書いてみました。
おしながき
- 松井選手の打撃データ(RETROSHEET)
- データを取得する
- 前処理 - Pandasでデータを読み込み&ややこしい行データからヒットの種類と落ちた場所を抽出する
- 可視化 - matplotlibでグラフを書いてみる
- 分析 - 絶好調な松井さんと引退前の松井さんの特徴について
松井選手の打撃データ(RETROSHEET)
まずデータですが、いつもどおりRETROSHEET(http://www.retrosheet.org/)のCSVデータを使っています。
松井秀喜選手がメジャーで実働していたのは2003年から2012年までなので、この期間のデータをGetし、データベース化します。
データベース化についてはお決まりのこちらのエントリーで作ったネタを使います。
最強の野球オープンデータ「Retrosheet」をPython+Vagrant+Ansibleで誰でも使えるようにしました - Lean Baseball
既にサーバーは作成済みで、2010~2014年のデータがある状態なので、足りない2009~2003年のデータを足すplaybookを作って実行しました。
ansible-playbook -i hosts data_create.yml
とかこんな感じでコマンドを叩いてしばらく待つとデータができていました*1。
データを取得する
データができたら、次のSQLを叩いて結果をCSVに保存します。
Hideki Matsuiさんの2004年打撃データの中でヒットの情報(安打/二塁打/三塁打/本塁打)を取得する
select e.game_id, e.event_id, e.event_cd, e.pitch_seq_tx, e.event_tx, e.bat_play_tx, e.battedball_cd, e.battedball_loc_tx from games as g left outer join events as e on g.game_id = e.game_id where e.bat_id = 'matsh001' and g.game_dt between 20040101 and 20041231 and e.event_cd in(20, 21, 22, 23) order by g.game_dt asc, e.event_id asc
from句ではevents(打席データ)とgames(試合データ)を結合しています。
select句のカラムはあとで解説するとして、where句の意味は、
where e.bat_id = 'matsh001'
eventsテーブルのbat_id(バッターの選手ID)カラムの中身がHideki Matsui(id:matsh001、IDの振り方は謎)のやつを取って来い!という意味です。
g.game_dt between 20040101 and 20041231
こちらは試合の期間です。2004/1/1~2004/12/31まで取得という意味です。
厳密に言えば、オフシーズンとプレーオフの期間(秋~冬)の期間は外すべきですが、このデータにプレーオフの情報は無いため、この記述でもデータは取れます。
e.event_cd in(20, 21, 22, 23)
eventsデータにはevent_cdという、打席のイベント(ヒット、三振、四球など)が記録されており、この中でヒットのモノだけを取得します。
- 20:安打
- 21:二塁打(エンタイトルツーベース、英語名称「Ground rule double」を含む)
- 22:三塁打
- 23:本塁打
これでSQLを実行し、結果を「hideki_matsui_2004.csv」という名前(csv)で保存します。
同じ要領で2011年のデータも取得します。
select e.game_id, e.event_id, e.event_cd, e.pitch_seq_tx, e.event_tx, e.bat_play_tx, e.battedball_cd, e.battedball_loc_tx from games as g left outer join events as e on g.game_id = e.game_id where e.bat_id = 'matsh001' and g.game_dt between 20110101 and 20111231 and e.event_cd in(20, 21, 22, 23) order by g.game_dt asc, e.event_id asc
日付の絞込を2004から2011に書き換え、ファイル名も「hideki_matsui_2011.csv」とでもしておきます。
前処理 - Pandasでデータを読み込み&ややこしい行データからヒットの種類と落ちた場所を抽出する
取得したcsvをPythonで料理!、、、する前に、一度ファイルの中身をチェックしてみましょう。
正直わけわからんですね!!!w
今回の分析で使う項目は、
- event_cd
- event_tx
- battedball_cd
の3つで、これらの意味が何となくわかればOKです。
event_cd
先ほどのSQLでも登場したカラムです。
打席で発生したイベント。0~25くらいまでありますが、SQLを発行した時点で以下に絞られています。
- 20:安打
- 21:二塁打(エンタイトルツーベース、英語名称「Ground rule double」を含む)
- 22:三塁打
- 23:本塁打
event_tx
event textの略。このエントリーの肝となるデータです。
打席で起きた結果とランナーの動きを示したテキストで、イベントの結果、発生場所、塁上の動き(走塁)をデリミタ("/"区切り)で表現しています。
例えば、
S9/G.1-3
という表記は、
「ゴロ性の当たりのライト前ヒット、一塁ランナーは三塁まで進塁」
を意味します。読み方ですが、
- 先頭は打球の種類。今回はヒットで絞っているため、S:Single(安打)、D:Double(二塁打)、T:Triple(三塁打)、HR:Homerun(本塁打)、DGR:Ground Rule Double(エンタイトルツーベース)のどれか。
- 数字は打球が落ちた場所。1(投手)~9(右翼手)の守備番号で表記。
- 打球の種類を表すアルファベット1文字。これは後述するbattedball_cdと同じ。
今回はこのテキストから打球の種類と落ちた場所を抽出します。
抽出するコードはこんな感じで書きました。
battedball_cd
打球の種類。
- G:Ground ball。日本風に言えばゴロ気味の当たり。転がって内野の間を抜けたりするアレ。
- F: Fly ball。上がった打球の事。外野の頭上を越える当たり(二塁打や三塁打、ホームランなど)が該当。
- L: Line drive。鋭い打球、ライナー性の打球のこと。単打もあれば、フェンスの低い球場の場合ライナー性のホームランが含まれる事も。
event_txからヒットの情報と場所ごとにカウントしてデータフレームを作る、というコードはこちら。
使い方はすぐこの後の章を参考にしてね。
可視化 - matplotlibでグラフを書いてみる
これらのコードを書き上げた後、いつもどおりIPython notebookで実行してみました。
トドメとしてこんなコードを書いてみるとあら不思議、外野ポジションごとに飛んだ打球の数と種類が出てきます。
dfpos2004 = pd.DataFrame(hit_charts2004.get('of')) dfpos2004.T.plot(kind='bar', stacked=True, ylim=(0, 100), title='Hideki Matsui(2004/NYY)')
dfpos2011 = pd.DataFrame(hit_charts2011.get('of')) dfpos2011.T.plot(kind='bar', stacked=True, ylim=(0, 100), title='Hideki Matsui(2011/OAK)')
分析 - 絶好調な松井さんと引退前の松井さんの特徴について
グラフを見ての感想&仮説はこちら。
あとはやきうが詳しい方と松井さんのファンにお任せします!
*1:ただ、1時間近くかかってたのでこのプロジェクトのコードを描き直そうかと思いました。多分無駄なこといっぱいしてる。