Edited at

RとSQLiteでMLBの一球速報データを自由気ままにいじってみた

More than 1 year has passed since last update.


はじめに

今年新卒で入社をしました、3度の飯よりアメリカ・メジャーリーグ(以下、MLB)が大好きなエンジニア見習いです。

MLBとITを絡めたネタで何か書いてみようと思い立ったので、本日はRとSQLiteを駆使しながらMLBの一球速報データで遊んでみた模様を記事にしてみました。


MLBの一球速報データ、実は楽に集められる

MLBの一球速報データは写真の様にMLB.com(公式サイトです)が"GameDay"という名のサービスとして配信しています。

その元データなのですが、http://gd2.mlb.com/components/下にXML形式で配置されており、XMLさえスクレイピング出来ればデータが楽々取得が出来る、という環境が整っていることを最近知りました。ファンにとっては天国と言っても過言では無い!

スクリーンショット 2016-11-23 10.30.10.png

でも、勝手にデータを使っても大丈夫なのかちょっと不安ですね。ライセンス面に関して記述がされているcopyritht.txtを確認してみました。


Only individual, non-commercial, non-bulk use of the Materials is permitted and any other use of the Materials is prohibited without prior written authorization from MLBAM.


とのこと。MLBファンが遊びで使う分には何の問題も無さそうなので、遠慮無く使って遊ぶことにしました(^ ^)


分析環境・使用データ


分析環境


  • R(3.3.1)

  • SQLite(3.13.0)


使用データ


  • 公式サイト配信のGameDayデータ


手順1:2016年シーズンの全データをスクレイピングしてDBに入れる


pitchRxのインポート

RにはGameDayデータのスクレイピング専用にpitchRxたるパッケージが存在します。まずはこれをインポートします。

# pitchRxパッケージのインストール

install.packages("pitchRx")

# pitchRxパッケージのインポート
library(pitchRx)

これでスクレイピングの準備が整いました。


スクレイピング実行/DBにデータを入れる

2016年シーズンの全投球データが詰まったXMLをスクレイピングして、SQLiteのテーブルに入れていきます。dplyrパッケージが別途必要になりますので、こちらもインポートします。

# dplyrパッケージのインストール

install.packages("dplyr")

# dplyrパッケージのインポート
library(dplyr)

# SQLiteのDBファイルを作成して、スクレイピングしたデータを入れる
db=src_sqlite("pitchfx.sqlite3",create=T)
scrape(start="2016-01-01",end=Sys.Date(),connect=db$con)

生成されたファイルpitchfx.sqlite3を読み込んでみると、"atbat", "action", "runner", "po(注:牽制データ)", "pitch"と5個のテーブルに分かれてスクレイピングしたデータが取得出来ていることが確認出来ます。


手順2:Rで分析する用のViewを作成する

ただ、見ると分かるのですが、5個のテーブル個々では全く使い物にならないレベルでデータが粗く、Rで読み込んでも意味がありません。

そこでRで読み込む用のデータを作成して、Viewとして保持するSQLを作成します。


gameday.sql

-- 分析用にALL_PITCH_DATAという名前のVIEWを作成します

CREATE VIEW ALL_PITCH_DATA
AS SELECT
atb.pitcher_name as name, -- 投手名
atb.batter_name as batter_name, -- 打者名
atb.stand as stand, -- 打者の立ち位置
pit.pitch_type as pitch_type, -- 球種
pit.start_speed as start_speed, -- 初速
pit.end_speed as end_speed, -- 終速
pit.spin_rate as spin_rate, -- 回転数
pit.spin_dir as spin_dir, -- 回転軸
pit.px as x, -- 投球ロケーション(x軸)
pit.pz as y, -- 投球ロケーション(y軸)
pit.break_angle as break_angle, -- 変化角
pit.break_length as break_length, -- 変化量
pit.des as des, -- 投球結果
atb.date as date -- 日時
FROM
atbat atb, -- 打席テーブル
pitch pit -- 投球データテーブル
WHERE
atb.url = pit.url -- スクレイピング先のxmlファイルのurl
AND atb.inning = pit.inning -- イニング
AND atb.inning_side = pit.inning_side -- 表/裏
AND atb.gameday_link = pit.gameday_link -- スクレイピング先のxmlファイルが表示されているGameDayのリンク
AND atb.next_ = pit.next_ -- 次打者の有無
AND atb.num = pit.num -- イベント番号
AND CAST(REPLACE(atb.date, '_', '') as NUMBER) BETWEEN 20160404 AND 20161002
-- キャンプ/プレーオフのデータは除外する処理
AND atb.pitcher_name is not null -- 投手名がnullのデータを除外
AND pit.pitch_type is not null -- 球種名がnullのデータを除外
;

これで一球速報データが完成しました。


手順3:整理したデータをRで読み込む

RのパッケージであるRSQLiteを使用して、先ほど作成したViewをRで読み込みます。


gameday.r

# RSQLiteのインポート

library(RSQLite)

# DB接続
driver=dbDriver("SQLite")
con=dbConnect(driver,dbname="pitchfx.sqlite3")

# View取得の実行
all_pitches=dbGetQuery(con,"SELECT * FROM ALL_PITCH_DATA")


Rファイルとして保存しておけば、次回からはソースを読み込ませるだけでデータが取れて楽チンです。


手順4:Rで自由気ままに遊ぶ

データのインポートまで出来たら自由気ままに遊ぶだけです。

私のオススメはrpivotTableパッケージにデータを食わせて、一球速報データを可視化することです。

# rpivotTableのダウンロード

install.packages("rpivotTable")

# rpivotTableのインポート
library(rpivotTable)

# rpivotTableにall_pitchesデータを食わせる
rpivotTable(all_pitches)

ここまで実行するとブラウザが立ち上がり、GUI上でデータをドラッグ&ドロップで組み替えてグラフ/表を作成出来る様になります。例えば

スクリーンショット 2016-12-03 14.07.25.png

投手別球種別の投球結果をマトリクスで整理したり

スクリーンショット 2016-12-03 14.14.15.png

球種別の球速分布をグラフとして描画したり

スクリーンショット 2016-12-03 14.45.04.png

もちろん、オーソドックスな散布図もコマンド不要で描けます(これは初速と終速の散布図です)。

R上で使ってみたいデータを加工して作成すれば、rpivotTableで可視化出来る内容も無限大に広がります。

何より、Rでplot等行うよりもグラフィックが美しく描画が出来る点が嬉しいですねー(plotは何だか味気が無くて汗)。何となくデータを入れてみるだけでも、色々と発見がありそうで個人的にはお気に入りなパッケージです。

以上、完全に趣味の話でした笑。もし少しでも楽しんで頂けたならば幸いです。


参考資料