メジャーリーグのデータ解析をしたい ( 21世紀限定HRランキング)
序論
ある程度まとまったデータの解析をしたいです.
でも, 興味のないデータを漫然と弄っても楽しくないです.
今回は, みんなが大好きなメジャーリーグのデータで遊びます.
野球に詳しくなって, さらにRの関数の使い方も練習できます.
さっそく, 21世紀のデータからホームラン数のランキングを作ります.
内容としては,
1. dataframeの扱い
2. apply関数の使用
3, applyを並列化して高速処理
あたりの勉強ができると思います.
最後にコピペ用ソースコードが載せてあるので, そこだけ見てもいいです.
メジャーリーグのデータで遊ぶ
データ取得と内容確認
メジャーリーグの試合データはいろいろ公開されていて, とても扱いやすいです.
まずは次のサイトからデータをダウンロードします.
Lahmanのdatabaseです. 2012年までのデータを使います.
http://www.seanlahman.com/baseball-archive/statistics/
camma区切りのデータが扱いやすいと重います.
ダウンロードしたら, 早速遊びます.
ワーキングディレクトリを適当に指定して, Rを起動.
データを読み込みます. 最初はBatting.csvです
Batting <- read.csv("Batting.csv")
中身はこんな感じ.
>head(Batting) playerID yearID stint teamID lgID G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old 1 aardsda01 2004 1 SFN NL 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 2 aardsda01 2006 1 CHN NL 45 43 2 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 45 3 aardsda01 2007 1 CHA AL 25 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 4 aardsda01 2008 1 BOS AL 47 5 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 5 5 aardsda01 2009 1 SEA AL 73 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NA 6 aardsda01 2010 1 SEA AL 53 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 NA
全選手分, 全年度の記録が詰まっているみたいです. これはすごい.
せっかくだからイチローの成績を確認したいです.
playerIDは, 5文字+2文字+"01" という構造みたいです. よく分かりませんけど.
suzuk + ic + 01ですかね. subset関数を利用して, playerID=="suzukic01"と条件指定して抽出.
> subset(Batting, playerID=="suzukic01") playerID yearID stint teamID lgID G G_batting AB R H X2B X3B HR RBI SB CS BB SO IBB HBP SH SF GIDP G_old 84890 suzukic01 2002 1 SEA AL 157 157 647 111 208 27 8 8 51 31 15 68 62 27 5 3 5 8 157 84891 suzukic01 2003 1 SEA AL 159 159 679 111 212 29 8 13 62 34 8 36 69 7 6 3 1 3 159 84892 suzukic01 2004 1 SEA AL 161 161 704 101 262 24 5 8 60 36 11 49 63 19 4 2 3 6 161 84893 suzukic01 2005 1 SEA AL 162 162 679 111 206 21 12 15 68 33 8 48 66 23 4 2 6 5 162 84894 suzukic01 2006 1 SEA AL 161 161 695 110 224 20 9 9 49 45 2 49 71 16 5 1 2 2 161 84895 suzukic01 2007 1 SEA AL 161 161 678 111 238 22 7 6 68 37 8 49 77 13 3 4 2 7 161 84896 suzukic01 2008 1 SEA AL 162 162 686 103 213 20 7 6 42 43 4 51 65 12 5 3 4 8 162 84897 suzukic01 2009 1 SEA AL 146 146 639 88 225 31 4 11 46 26 9 32 71 15 4 2 1 1 NA 84898 suzukic01 2010 1 SEA AL 162 162 680 74 214 30 3 6 43 42 9 45 86 13 3 3 1 3 NA 84899 suzukic01 2011 1 SEA AL 161 161 677 80 184 22 3 5 47 40 7 39 69 13 0 1 4 11 161 84900 suzukic01 2012 1 SEA AL 95 NA 402 49 105 15 5 4 28 15 2 17 40 4 0 0 4 10 NA 84901 suzukic01 2012 2 NYA AL 67 NA 227 28 73 13 1 5 27 14 5 5 21 1 2 5 1 2 NA
去年までの結果です. ヒット数はHですね. 半端じゃ無いH数です.
HRがホームランの数でしょうね. 今日はHRを使います.
21世紀のHRランキングを作る
工夫したランキングを作ります. 今回は21世紀のホームラン数を比べます.
指定する条件だけ変えれば, いくらでも好きなランキングが作れます.
21世紀のホームラン数を得るのに必要な処理を確認すると,
1. 21世紀の分の成績を抽出
2. 各選手でホームラン数の合計を計算
3. ホームラン数で並べ替え
ですね. 順番にやります.
1. 21世紀の成績を抽出
これは簡単
# 21世紀の成績がほしい Batting <- subset(Batting, yearID>2001)
ですね.
次.
2. 各選手でホームラン数の合計を計算.
これはもう少し細かく考えると,
2.1 選手の名前のリストをつくる
2.2 選手の名前からHR数の合計を返す関数をつくる
2.3 2.1のリストの各要素に, 2.2の関数を適用する
ですかね.
順番にやります.
# 選手の名前のリストを取り出す. # playerIDには毎年同じ名前が出てくるので, uniqueで圧縮 players <- unique(Batting$playerID) # 名前からホームラン数の和を計算する関数 compute.HR <- function(pid){ d <- subset(Batting, playerID == pid) sum(d$HR) } # playersの各要素ににcompute.HRを HR <- sapply(players, compute.HR)
HR数のベクトルが欲しいので, sapplyですね.
apply周りの関数はlapplyとsapplyだけ分かっておけば生きていける気がします.
これで各選手の, 21世紀のHR数がわかりました.
3. HR数で並べ替え
選手と21世紀HR数のdataframeを作って, HR数で並べ替えます
HRlist <- data.frame(Player = players, HR=HR) # HR数で降順に並べ替えたい # order関数を使います. 降順なので, decreasing=TRUEにします. HRlist <- HRlist[order(R$HR, decreasing=TRUE), ]
結果を見てみます.
>head(HRlist) Player HR 2495 pujolal01 438 2657 rodrial01 406 858 dunnad01 387 2287 ortizda01 363 2951 soriaal01 351 1654 konerpa01 338
できました.
1位は大正義プホルス. TEXで復活して欲しい.
2位はおクスリA-ROD.
続いて, 三振かホームランか四球のアダム・ダン
レッドソックス優勝に貢献したオルティズ
広島カープにいるはずだったソリアーノ
最後は誰ですか分かりません.
(追記)
ホワイトソックスのポール・コネルコでした.
知らなかった.
並列化して高速に処理
applyのところでとても時間がかかります.
選手が多いですから, 仕方ないのですが.
> time_nonParallel <- system.time(HR <- sapply(players, compute.HR)) > time_nonParallel ユーザ システム 経過 78.915 5.190 84.220
遅いです.
それぞれの処理は独立しているので, 並列計算して速く処理できませんかね.
やってみます. parallelパッケージのparSapplyを使います.
# 並列化パッケージを使います library(parallel) # 計算クラスタを4つ作る cl <- makeCluster(4,type="SOCK") # データをクラスタに持たせる clusterExport(cl, c("Batting")) # parSapplyで並列計算 time_Parallel <- system.time(HR2 <- parSapply(cl, players, compute.HR)) # おわり stopCluster(cl)
これで速くなりますかね? 比べてみます
> time_nonParallel ユーザ システム 経過 78.915 5.190 84.220 > time_Parallel ユーザ システム 経過 25.709 9.515 80.928
速いです. 並列化してよかった.
まとめ
コピペ用にコードをまとめます.
library(parallel) cl <- makeCluster(4,type="SOCK") Batting <- read.csv("Batting.csv") # head(Batting) # 21世紀の成績がほしい Batting <- subset(Batting, yearID>2001) # head(Batting) # 名前からホームラン数の和を計算する関数 compute.HR <- function(pid){ d <- subset(Batting, playerID == pid) sum(d$HR) } # 選手の名前のリストを取り出す. # uniqueで圧縮 players <- unique(Batting$playerID) # 名前のリストに関数を適用 sapplyを使えばOK # データをクラスタに持たせて並列計算 clusterExport(cl, c("Batting")) HR <- parSapply(cl, players, compute.HR) stopCluster(cl) # 新しくデータフレームを作成 HRlist <- data.frame(Player = players, HR=HR) # HR数で並べ替え HRlist <- HRlist[order(HRlist$HR,decreasing=TRUE),] # head(HRlist)
参考文献
Analyzing Baseball Data with R (Chapman & Hall/CRC The R Series)
- 作者: Max Marchi
- 出版社/メーカー: Chapman and Hall/CRC
- 発売日: 2013/10/30
- メディア: Kindle版
- この商品を含むブログを見る