Plyrを間違って使用していると思います。これが「効率的な」プライヤコードであるかどうか誰かに教えてもらえますか?
require(plyr)
plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume))
少しコンテキスト:私はいくつかの大きな集計の問題を抱えており、それぞれに時間がかかっていることに気づきました。問題を解決しようとして、Rでのさまざまな集計手順のパフォーマンスに興味を持ちました。
私はいくつかの集計方法をテストしましたが、一日中待っていました。
ようやく結果が戻ってきたとき、プライア方式と他の方式との間に大きなギャップがあることに気づきました。
次のコードを実行しました(新しいデータフレームパッケージを確認しているときにチェックアウトすると思いました)。
require(plyr)
require(data.table)
require(dataframe)
require(rbenchmark)
require(xts)
plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume))
t.apply <- function(dd) unlist(tapply(dd$volume, dd$price, sum))
t.apply.x <- function(dd) unlist(tapply(dd[,2], dd[,1], sum))
l.apply <- function(dd) unlist(lapply(split(dd$volume, dd$price), sum))
l.apply.x <- function(dd) unlist(lapply(split(dd[,2], dd[,1]), sum))
b.y <- function(dd) unlist(by(dd$volume, dd$price, sum))
b.y.x <- function(dd) unlist(by(dd[,2], dd[,1], sum))
agg <- function(dd) aggregate(dd$volume, list(dd$price), sum)
agg.x <- function(dd) aggregate(dd[,2], list(dd[,1]), sum)
dtd <- function(dd) dd[, sum(volume), by=(price)]
obs <- c(5e1, 5e2, 5e3, 5e4, 5e5, 5e6, 5e6, 5e7, 5e8)
timS <- timeBasedSeq('20110101 083000/20120101 083000')
bmkRL <- list(NULL)
for (i in 1:5){
tt <- timS[1:obs[i]]
for (j in 1:8){
pxl <- seq(0.9, 1.1, by= (1.1 - 0.9)/floor(obs[i]/(11-j)))
px <- sample(pxl, length(tt), replace=TRUE)
vol <- rnorm(length(tt), 1000, 100)
d.df <- base::data.frame(time=tt, price=px, volume=vol)
d.dfp <- dataframe::data.frame(time=tt, price=px, volume=vol)
d.matrix <- as.matrix(d.df[,-1])
d.dt <- data.table(d.df)
listLabel <- paste('i=',i, 'j=',j)
bmkRL[[listLabel]] <- benchmark(plyr(d.df), plyr(d.dfp), t.apply(d.df),
t.apply(d.dfp), t.apply.x(d.matrix),
l.apply(d.df), l.apply(d.dfp), l.apply.x(d.matrix),
b.y(d.df), b.y(d.dfp), b.y.x(d.matrix), agg(d.df),
agg(d.dfp), agg.x(d.matrix), dtd(d.dt),
columns =c('test', 'elapsed', 'relative'),
replications = 10,
order = 'elapsed')
}
}
テストは5e8までチェックすることになっていたが、時間がかかりすぎた-主にプライヤーが原因だった。 5e5ファイナルテーブルは問題を示しています:
$`i= 5 j= 8`
test elapsed relative
15 dtd(d.dt) 4.156 1.000000
6 l.apply(d.df) 15.687 3.774543
7 l.apply(d.dfp) 16.066 3.865736
8 l.apply.x(d.matrix) 16.659 4.008422
4 t.apply(d.dfp) 21.387 5.146054
3 t.apply(d.df) 21.488 5.170356
5 t.apply.x(d.matrix) 22.014 5.296920
13 agg(d.dfp) 32.254 7.760828
14 agg.x(d.matrix) 32.435 7.804379
12 agg(d.df) 32.593 7.842397
10 b.y(d.dfp) 98.006 23.581809
11 b.y.x(d.matrix) 98.134 23.612608
9 b.y(d.df) 98.337 23.661453
1 plyr(d.df) 9384.135 2257.972810
2 plyr(d.dfp) 9384.448 2258.048123
これは正解? plyr2250xがdata.table
より遅いのはなぜですか?そして、なぜ新しいデータフレームパッケージを使用しても違いが生じなかったのですか?
セッション情報は次のとおりです。
> sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-Apple-darwin9.8.0/x86_64 (64-bit)
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] xts_0.8-6 Zoo_1.7-7 rbenchmark_0.3 dataframe_2.5 data.table_1.8.1 plyr_1.7.1
loaded via a namespace (and not attached):
[1] grid_2.15.1 lattice_0.20-6 tools_2.15.1
なぜとても遅いのですか?ちょっとした調査で、2011年8月からのメールグループの投稿が見つかりました。パッケージの作成者である@hadley、 states
これは、ddplyが常にデータフレームで機能する方法の欠点です。 data.frameの代わりにsummaryを使用すると(data.frameが非常に遅いため)少し速くなりますが、ddplyアプローチのこの基本的な制限を克服する方法をまだ考えています。
efficient plyrコードであることについても私は知りませんでした。たくさんのパラメータテストとベンチマークを行った後、もっとうまくやれるように見えます。
コマンドのsummarize()
は、純粋で単純な単なるヘルパー関数です。まだ単純ではないものには役立たず、_.data
_および.(price)
引数をより明示的にすることができるため、独自のsum関数に置き換えることができます。結果は
_ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )
_
summarize
は素晴らしいように見えるかもしれませんが、単純な関数呼び出しよりも速くはありません。それは理にかなっている; summarize
の- code に対する小さな関数を見てください。改訂された式を使用してベンチマークを実行すると、顕著な利益が得られます。 plyrを間違って使用したという意味ではありません。使用していないので、効率的ではありません。あなたがそれでできることは何もそれを他のオプションと同じくらい速くしません。
私の意見では、最適化された関数は明確ではなく、data.tableと比較して途方もなく遅い(60%のゲインがあっても)とともに精神的に解析する必要があるため、まだ悪臭を放っています。
上記と同じ thread で、plyrの遅さに関して、plyr2プロジェクトが言及されています。質問に対する最初の回答の時から、plyrの作者はplyrの後継としてdplyr
をリリースしました。 plyrとdplyrの両方がデータ操作ツールとして請求され、主な関心は集約ですが、パフォーマンスを向上させるためにバックエンドが作り直されているため、比較のために新しいパッケージのベンチマーク結果に関心がある場合があります。
_plyr_Original <- function(dd) ddply( dd, .(price), summarise, ss=sum(volume))
plyr_Optimized <- function(dd) ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )
dplyr <- function(dd) dd %.% group_by(price) %.% summarize( sum(volume) )
data_table <- function(dd) dd[, sum(volume), keyby=price]
_
dataframe
パッケージは、行列関数のバージョンとともに、CRANから削除され、その後テストから削除されました。
_i=5, j=8
_ベンチマークの結果は次のとおりです。
_$`obs= 500,000 unique prices= 158,286 reps= 5`
test elapsed relative
9 data_table(d.dt) 0.074 1.000
4 dplyr(d.dt) 0.133 1.797
3 dplyr(d.df) 1.832 24.757
6 l.apply(d.df) 5.049 68.230
5 t.apply(d.df) 8.078 109.162
8 agg(d.df) 11.822 159.757
7 b.y(d.df) 48.569 656.338
2 plyr_Optimized(d.df) 148.030 2000.405
1 plyr_Original(d.df) 401.890 5430.946
_
間違いなく、最適化が少し役に立ちました。 _d.df
_関数を見てください。彼らはただ競争することができません。
Data.frame構造の速度の遅さについて少し説明するために、より大きなテストデータセット(_i=8,j=8
_)を使用したdata_tableとdplyrの集約時間のマイクロベンチマークを示します。
_$`obs= 50,000,000 unique prices= 15,836,476 reps= 5`
Unit: seconds
expr min lq median uq max neval
data_table(d.dt) 1.190 1.193 1.198 1.460 1.574 10
dplyr(d.dt) 2.346 2.434 2.542 2.942 9.856 10
dplyr(d.df) 66.238 66.688 67.436 69.226 86.641 10
_
Data.frameはまだほこりの中に残っています。それだけでなく、データ構造にテストデータを入力するための経過したsystem.timeは次のとおりです。
_`d.df` (data.frame) 3.181 seconds.
`d.dt` (data.table) 0.418 seconds.
_
data.frameの作成と集約の両方がdata.tableの作成と集約よりも遅い
Data.frameの操作in R isいくつかの選択肢よりも遅いですが、ベンチマークが示すように、組み込みのR関数が水からプライヤーを吹き飛ばします。 dplyrのようにdata.frameを管理することでさえ、組み込みを改善しますが、最適な速度は得られません。ここで、data.table 高速作成と集約の両方でand data.tableは、data.framesの操作中/処理中に実行します。
最終的には...
itがdata.frame操作を処理および管理する方法のため、Plyrは低速です。
[パント::元の質問へのコメントを参照]。
_## R version 3.0.2 (2013-09-25)
## Platform: x86_64-pc-linux-gnu (64-bit)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] microbenchmark_1.3-0 rbenchmark_1.0.0 xts_0.9-7
## [4] Zoo_1.7-11 data.table_1.9.2 dplyr_0.1.2
## [7] plyr_1.8.1 knitr_1.5.22
##
## loaded via a namespace (and not attached):
## [1] assertthat_0.1 evaluate_0.5.2 formatR_0.10.4 grid_3.0.2
## [5] lattice_0.20-27 Rcpp_0.11.0 reshape2_1.2.2 stringr_0.6.2
## [9] tools_3.0.2
_