ric*_*rdo 58 r plyr dataframe data.table
我想我正在使用plyr错误.有人可以告诉我这是否是"高效"的plyr代码?
require(plyr)
plyr <- function(dd) ddply(dd, .(price), summarise, ss=sum(volume))
Run Code Online (Sandbox Code Playgroud)
一点背景:我有一些大的聚合问题,我注意到他们每个人都花了一些时间.在尝试解决问题时,我开始对R中各种聚合过程的性能感兴趣.
我测试了一些聚合方法 - 并且发现自己整天都在等待.
当我最终得到结果时,我发现了plyr方法和其他方法之间的巨大差距 - 这让我觉得我做错了.
我运行了以下代码(我以为我在查看时会查看新的数据帧包):
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')
}
}
Run Code Online (Sandbox Code Playgroud)
该测试应该检查到5e8,但它花了太长时间 - 主要是由于plyr.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
Run Code Online (Sandbox Code Playgroud)
这是正确的吗?为什么plyr比2250x慢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
Run Code Online (Sandbox Code Playgroud)
The*_*ell 51
为什么这么慢?一个小小的研究发现了一个邮件组,发布于2011年8月,包裹作者@hadley 说
这是ddply始终与数据帧一起使用的方式的缺点.如果使用summarize而不是data.frame会更快一些(因为data.frame非常慢),但我仍然在思考如何克服ddply方法的这个基本限制.
至于高效的 plyr代码,我也不知道.经过一系列的参数测试和基准测试后,看起来我们可以做得更好.
在summarize()您的命令是一个公正的帮手功能,纯粹而简单.我们可以用我们自己的sum函数替换它,因为它没有帮助任何非简单的东西,.data并且.(price)可以使参数更明确.结果是
ddply( dd[, 2:3], ~price, function(x) sum( x$volume ) )
Run Code Online (Sandbox Code Playgroud)
在summarize看似不错,但它仅仅是不超过一个简单的函数调用更快.这说得通; 只要看看我们的小功能,相对于代码的summarize.使用修订后的公式运行基准测试可获得显着的收益.不要认为这意味着你已经错误地使用了plyr,你没有,它只是效率不高; 你无能为力将使它与其他选择一样快.
在我看来,优化的功能仍然很糟糕,因为它不清楚,必须进行心理解析,与data.table相比仍然是非常慢的(即使增益为60%).
在上面提到的同一个线程中,关于plyr的缓慢性,提到了plyr2项目.自从plyr作者dplyr作为plyr的继承者发布的问题的原始答案的时间.虽然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]
Run Code Online (Sandbox Code Playgroud)
该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
Run Code Online (Sandbox Code Playgroud)
毫无疑问,优化有所帮助.看看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
Run Code Online (Sandbox Code Playgroud)
data.frame 仍然留在尘埃中.不仅如此,而且这里是使用测试数据填充数据结构的已用系统时间:
`d.df` (data.frame) 3.181 seconds.
`d.dt` (data.table) 0.418 seconds.
Run Code Online (Sandbox Code Playgroud)
data.frame的创建和聚合都比data.table的创建和聚合慢.
与data.frame工作中 [R 是比一些替代速度较慢,但作为基准测试显示,内置的R的功能和吹plyr出来的水.即使像dplyr那样管理data.frame,也会改进内置函数,但不能提供最佳速度; data.table 在创建和聚合方面都更快,而 data.table在使用/ on data.frames时执行的操作更快.
到底...
Plyr是缓慢的,因为的方式它的工作原理与和管理data.frame操作.
[punt ::查看对原始问题的评论].
## 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5773 次 |
| 最近记录: |