読者です 読者をやめる 読者になる 読者になる

300億円欲しい

メジャーリーグのデータ解析します

メジャーリーグのデータ解析をしたい (ダルビッシュがすごい)

R 野球 セイバーメトリクス

序論

Rを使ってメジャーリーグのデータ解析がしたいです.

全ての試合結果データが公開されています.
retrosheetという名前で, 無料で使えます.
http://www.retrosheet.org/game.htm
せっかくなので使います.

試合結果データを整形してcsvファイルにしたあとで,
Rを使ってダルビッシュの2013年の成績をグラフにします.

データの内容と整形

全試合の出場選手とその全打席結果データがダウンロードできます.
http://www.retrosheet.org/game.htm
2013年のデータを見てみます.
Regular Season のEvent Fileを落とします. 2013eve.zipです.
zipを展開すると, たくさんのファイルが

gghatano:2013eve taku$ ls
2013ANA.EVA	2013LAN.EVN	2013TBA.EVA	COL2013.ROS	SDN2013.ROS
2013ARI.EVN	2013MIA.EVN	2013TEX.EVA	DET2013.ROS	SEA2013.ROS
2013ATL.EVN	2013MIL.EVN	2013TOR.EVA	HOU2013.ROS	SFN2013.ROS
2013BAL.EVA	2013MIN.EVA	2013WAS.EVN	KCA2013.ROS	SLN2013.ROS
2013BOS.EVA	2013NYA.EVA	ANA2013.ROS	LAN2013.ROS	TBA2013.ROS
2013CHA.EVA	2013NYN.EVN	ARI2013.ROS	MIA2013.ROS	TEAM2013
2013CHN.EVN	2013OAK.EVA	ATL2013.ROS	MIL2013.ROS	TEX2013.ROS
2013CIN.EVN	2013PHI.EVN	BAL2013.ROS	MIN2013.ROS	TOR2013.ROS
2013CLE.EVA	2013PIT.EVN	BOS2013.ROS	NYA2013.ROS	WAS2013.ROS
2013COL.EVN	2013SDN.EVN	CHA2013.ROS	NYN2013.ROS
2013DET.EVA	2013SEA.EVA	CHN2013.ROS	OAK2013.ROS
2013HOU.EVA	2013SFN.EVN	CIN2013.ROS	PHI2013.ROS
2013KCA.EVA	2013SLN.EVN	CLE2013.ROS	PIT2013.ROS

行われた試合の動きが各チームごとに記録されています.

Rで扱いやすい形にしたいです.
csvファイルにして整理します.
Analysing Baseball Data with Rで提供されるコードを改変して, 整形用スクリプトを作って適用します.
整形の手法は後日詳しく説明します.

使用結果です. 整形したデータファイルはgithubにあります.

> data2013 <- read.csv("all2013.csv")
> names(data2013) <-  read.csv("fields.csv")[,"Header"]
> dim(data2013)
[1] 190907     97
>
> head(data2013)[,1:10]
       GAME_ID AWAY_TEAM_ID INN_CT BAT_HOME_ID OUTS_CT BALLS_CT STRIKES_CT PITCH_SEQ_TX AWAY_SCORE_CT HOME_SCORE_CT
1 ANA201304090          OAK      1           0       0        0          1           CX             0             0
2 ANA201304090          OAK      1           0       1        2          2       CBCFBX             0             0
3 ANA201304090          OAK      1           0       2        3          1        BBCBB             0             0
4 ANA201304090          OAK      1           0       2        3          1        BBCBB             0             0
5 ANA201304090          OAK      1           0       2        3          1        BCBBX             0             0
6 ANA201304090          OAK      1           0       2        0          0            X             1             0

97変数で1つの打席の状態と結果を表しています.
全打席は190,907回あったみたいです.

...変数が多すぎて分かりません.
説明はここに書いてあります.
http://www.retrosheet.org/eventfile.htm
よくわかりました.

試合の動きを少しだけ確認します.
試合開始直後から, アウトカウントと得点, 打席の内容とその結果の様子を抜き出しました.

> head(data2013)[c("OUTS_CT", "AWAY_SCORE_CT","PITCH_SEQ_TX","EVENT_TX")]
  OUTS_CT AWAY_SCORE_CT PITCH_SEQ_TX       EVENT_TX
1       0             0           CX           53/G
2       1             0       CBCFBX           63/G
3       2             0        BBCBB              W
4       2             0        BBCBB          W.1-2
5       2             0        BCBBX   S8/G.2-H;1-2
6       2             1            X S56/L+.2-3;1-2

暗号解読です.
PITCH_SEQ_TXは投球結果です. 以下の通りらしいです.
この表を使って解読します.

+ following pickoff throw by the catcher
* indicates the following pitch was blocked by the catcher
. marker for play not involving the batter
1 pickoff throw to first
2 pickoff throw to second
3 pickoff throw to third
> Indicates a runner going on the pitch
B ball
C called strike
F foul
H hit batter
I intentional ball
K strike (unknown type)
L foul bunt
M missed bunt attempt
N no pitch (on balks and interference calls)
O foul tip on bunt
P pitchout
Q swinging on pitchout
R foul ball on pitchout
S swinging strike
T foul tip
U unknown or missed pitch
V called ball because pitcher went to his mouth
X ball put into play by batter
Y ball put into play on pitchout

めんどくさい.

暗号解読. 再掲. 試合開始からの動き.

> head(data2013)[c("OUTS_CT", "AWAY_SCORE_CT","PITCH_SEQ_TX","EVENT_TX")]
  OUTS_CT AWAY_SCORE_CT PITCH_SEQ_TX       EVENT_TX
1       0             0           CX           53/G
2       1             0       CBCFBX           63/G
3       2             0        BBCBB              W
4       2             0        BBCBB          W.1-2
5       2             0        BCBBX   S8/G.2-H;1-2
6       2             1            X S56/L+.2-3;1-2

先頭打者から見ていきます.
投球結果はCX.
CXはcalled strike からの ball put into play by batterです.
つまり, 初球は見逃しストライク.
2球目がバットにあたってインフィールドに飛んだ, ということでしょうね.
その結果は. EVENT_TX.
53/Gはサードからファーストに送球されたゴロ, ということです.
つまり, サードゴロで1アウト.

2人目.
CBCFBXは
見逃し, ボール, 見逃し, ファウルボール, ヒッティング.
打ったボールは63/G. 6はショート. 3はファースト. Gはゴロ
つまりショートゴロでファースト送球で2アウト.

3人目はBBCBBで四球.
4人目はBBCBBで四球. ランナーは1塁から2塁へ.
5人目は5球目を当てました. S8はセンターへのSingleヒットです.
ランナーは2塁からホーム(Home)へ, 1塁ランナーは2塁へ.
アウェイチームが1点とったのでAWAY_SCOREが増えています.

細かいですが, ほとんど全ての試合進行が把握できますね.

試合と選手でデータを統合すれば, 各選手の試合ごとの成績が得られます.
これでなんでもできますね!

ダルビッシュの成績推移を知りたい.

試合ごとの結果がわかるので, 成績の変化もわかります.
今回は2013年のダルビッシュの各種成績の推移を視覚化します.

タイトルを取った奪三振から.

ダルビッシュの奪三振数推移

比較のために岩隈とバーランダーに犠牲になってもらいました.

f:id:gg_hatano:20131213181008p:plain
オールスター戦の前後で停滞しています.
1度故障者リストに入りましたね.

ダルビッシュの四球数推移

f:id:gg_hatano:20131213181024p:plain
ダルビッシュすごい

ダルビッシュの被ホームラン数推移

f:id:gg_hatano:20131213181047p:plain
バーランダーは安定して打たれませんね.
対して, ダルビッシュと岩隈は調子が悪いとボコボコ打たれるのでしょうか.

ダルビッシュの被安打数推移

f:id:gg_hatano:20131213181147p:plain
ダルビッシュすごい.

結論

ダルビッシュすごい
この成績でどうして13勝9敗なんですかね

ソースコード

扱うcsvファイルは2種類です.

2013年の試合結果が詰まったデータファイルがall2013.csv
変数のラベルつけ用のcsvファイルがfields.csvです.

偉いからgithubにまとめました.
https://github.com/gghatano/AnalyzingBaseballData

グラフ描画のためのRソースコードです.
csvファイルが有る場所で実行すればOKです.

library(plyr)
# setwd("csvファイルがある場所")
# 2013年の整形済みデータを利用
data2013 <- read.csv("all2013.csv", header= FALSE)
fields <- read.csv("fields.csv")
names(data2013) <- fields[, "Header"]

# playerIDをつけます
dar.id <- "darvy001"
iwakuma.id <- "iwakh001"
verland.id <- "verlj001"

# 選手ごとにデータを抽出
dar.data <- subset(data2013, PIT_ID ==dar.id)
iwakuma.data <- subset(data2013, PIT_ID ==iwakuma.id)
verland.data <- subset(data2013, PIT_ID ==verland.id)

# データをまとめる関数
createdata <- function(d){
  # 試合の日にちを抽出
  d$Date <- as.Date(substr(d$GAME_ID, 4, 11), format = "%Y%m%d")
  d <- arrange(d, Date) 
  
  # 三振のデータが欲しいなら EVENT_CD は3です
  d$SO <- ifelse(d$EVENT_CD == 3, 1, 0)
  d$cumSO <- cumsum(d$SO)
  d[, c("Date", "cumSO")]
}

dar.SOdata <- createdata(dar.data)
iwakuma.SOdata <- createdata(iwakuma.data)
verland.SOdata <- createdata(verland.data)

# 適当にプロット
plot(dar.SOdata, type ="l", lwd =2,xlab = "Date(Month)", ylab = "SO")
lines(iwakuma.SOdata, lwd = 2, col = "grey")
lines(verland.SOdata, lwd = 2, col = "red")
legend("topleft", 
       legend = c(paste("Darvish (", max(dar.SOdata$cumSO), ")", sep=""),
                  paste("Iwakuma (", max(iwakuma.SOdata$cumSO), ")", sep=""), 
                  paste("Verlander (", max(verland.SOdata$cumSO), ")", sep="")), 
       lwd = 2, col = c("black", "grey", "red"))

EVENT_CDの対応表.

Unknown event
1 No event
2 Generic out
3 Strikeout
4 Stolen base
5 Defensive indifference
6 Caught stealing
7 Pickoff error
8 Pickoff
9 Wild pitch
10 Passed ball
11 Balk
12 Other advance
13 Foul error
14 Walk
15 Intentional walk
16 Hit by pitch
17 Interference
18 Error
19 Fielder's choice
20 Single
21 Double
22 Triple
23 Home run
24 Missing play

なので, さっきのコードで

  # 三振のデータが欲しいなら EVENT_CD は3です
  d$SO <- ifelse(d$EVENT_CD == 23, 1, 0)
  # 3 を 23にするとホームランになります.

被本塁打数もすぐに分かります.

参考文献

Analyzing Baseball Data with R (Chapman & Hall/CRC The R Series)

Analyzing Baseball Data with R (Chapman & Hall/CRC The R Series)