効率的にデータフレームの処理がしたい(doByパッケージとは)
序論
Rでデータフレームを効率的に弄りたいです.
plyrパッケージはとても優秀です. 使いましょう.
doByパッケージもとても優秀です. 使いましょう.
irisデータの処理
データフレームを処理する道具として, plyrパッケージを紹介します.
みんな大好きirisデータで実験します.
> data(iris) > head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa > unique(iris$Species) [1] setosa versicolor virginica Levels: setosa versicolor virginica
irisは複数種の菖蒲に関するデータです.
Sepalはがく片, Petalは花びらという意味です.
irisデータには, それぞれの大きさと幅の数値が入っています.
Sepal.Length で菖蒲のがくの長さです.
最後の列に菖蒲の種類が記録されています.
このirisデータ. R界隈ではよく使われます.
このデータについて, 各種類別平均値が欲しい場合を考えます.
つまり, Speciesで分けて, それぞれの値を平均したものが知りたい場合を考えます.
apply関数を使う
大人なのでapplyを使います.
> iris_setosa <- subset(iris, iris$Species == "setosa") > iris_setosa_mean <- sapply(iris_setosa[,1:4], mean) > iris_setosa_mean Sepal.Length Sepal.Width Petal.Length Petal.Width 5.006 3.428 1.462 0.246
出ました.
残り2つの種類のアヤメで同様の処理を行って, 結果をまとめればいいですね.
plyrパッケージを使ってデータ処理
残り2つの種類のアヤメで同様の処理を行うのは面倒です.
最後に結果をまとめるのも面倒です.
全部自動的にやってくれる関数が欲しいです.
探せばあります. plyrパッケージです.
http://cran.r-project.org/web/packages/plyr/plyr.pdf
種類別に処理してから結果をまとめて出力してくれます. 今回はddplyを使います
> library(plyr) > iris_mean_plyr <- ddply(iris, .(Species), # Speciesで分割する + summarize, # 以下の計算をして, まとめて出力 + Sepal.Length = mean(Sepal.Length), + Sepal.Width = mean(Sepal.Width), + Petal.Length = mean(Petal.Length), + Petal.Width = mean(Petal.Width)) > iris_mean_plyr Species Sepal.Length Sepal.Width Petal.Length Petal.Width 1 setosa 5.006 3.428 1.462 0.246 2 versicolor 5.936 2.770 4.260 1.326 3 virginica 6.588 2.974 5.552 2.026
分割して, 処理して, まとめてくれました.
doByパッケージを使ってデータ処理.
もっと行数を減らしたいです. doByパッケージを使います.
これも, 分割して, 処理して, まとめてくれます.
> library(doBy) > iris_mean_doBy <- summaryBy( . ~ Species, + data = iris, + FUN = mean, + keep.names = TRUE) > iris_mean_doBy Species Sepal.Length Sepal.Width Petal.Length Petal.Width 1 setosa 5.006 3.428 1.462 0.246 2 versicolor 5.936 2.770 4.260 1.326 3 virginica 6.588 2.974 5.552 2.026
分割して, 処理して, まとめてくれました.
MLBデータの処理で比較
plyrとdoBy. 今回は同じ処理が出来ました.
何が違うのでしょうかね. 処理速度ですか?
実験してみます. 野球のデータを使います.
メジャーリーグの2013年シーズンの全投球結果に関するデータが公開されています.
データをpitch f/xから持ってきます. 詳しくは前回参照
http://gg-hogehoge.hatenablog.com/entry/2013/12/21/075023
> data2013 <- read.csv("2013.csv")
1シーズン分で430MBあります. 中身を少し見てみます.
> head(data2013[,c("sv_id", "pitcher_name", "start_speed", "end_speed")]) sv_id pitcher_name start_speed end_speed 333 130222_130329 Derek Holland 93.2 86.2 334 130222_130341 Derek Holland 93.4 86.4 335 130222_130402 Derek Holland 84.3 76.9 336 130222_130444 Derek Holland 92.6 86.2 337 130222_130500 Derek Holland 82.8 77.0 338 130222_130529 Derek Holland 85.2 79.2
投手の名前と初速と終速がマイル表示で入っています.
先頭の行から,
2013年の2月22日の13時03分29秒に Derek Holland さん 93.2マイルの球を投げた
ことがわかります.
このデータで処理速度の調査をします.
全ての投球結果について, 直球の平均球速ランキングを作りたいです.
つまり, 投手の名前で分割して, 直球のデータについて平均を出してまとめます.
plyrとdoByが使えますね. 同じ処理をさせて, 速度を比較してみました.
> plyr_time user system elapsed 16.303 12.998 30.019 > doBy_time user system elapsed 0.255 0.045 0.300
意識が高いので見える化します.
doByを使いましょう.
ついでにメジャーリーグの直球の速さランキングです.
> head(FF_start) pitcher_name start_speed end_speed 1 Bruce Rondon 159.7885 147.0118 2 Aroldis Chapman 158.1140 145.4615 3 Kelvin Herrera 158.0158 145.2006 4 Nathan Jones 157.2777 144.2170 5 Trevor Rosenthal 156.5369 143.4561 6 Duke Welker 156.4418 144.7118
2位のチャップマンは171キロまで出ます.
チャップマン 人類最速171キロ!! - YouTube
まとめ
doByとplyrはどうやって使い分けすればいいのでしょうか.
良くわからないので誰か教えてください.
ソースコード
data2013 <- read.csv("2013.csv") data2013 <- subset(data2013, data2013$sv_id != "NA") attach(data2013) start_speed <- as.numeric(start_speed) end_speed <- as.numeric(end_speed) detach(data2013) data2013_FF <- subset(data2013, data2013$pitch_type=="FF") library(plyr) plyr_time <- system.time(FF_speed_mean <- ddply(data2013_FF, .(pitcher_name), summarize, FF_start_speed = mean(start_speed), FF_end_speed = mean(end_speed), .progress = "text") ) library(doBy) doBy_time <- system.time(FF_speed_mean2 <- summaryBy(start_speed + end_speed ~ pitcher_name, data = data2013_FF, FUN = mean, keep.names = TRUE)) plyr_time doBy_time