是否通过()功能使越来越多(does the by( ) function make growing

2019-08-03 12:27发布

是否by功能做出在时间一长一个元素的列表?

我需要处理用约4M观测由系数列分组的数据帧。 这种情况类似于下面的例子:

> # Make 4M rows of data
> x = data.frame(col1=1:4000000, col2=10000001:14000000)
> # Make a factor
> x[,"f"] = x[,"col1"] - x[,"col1"] %% 5
>   
> head(x)
  col1     col2 f
1    1 10000001 0
2    2 10000002 0
3    3 10000003 0
4    4 10000004 0
5    5 10000005 5
6    6 10000006 5

现在, tapply上的一列需要的合理时间:

> t1 = Sys.time()
> z = tapply(x[, 1], x[, "f"], mean)
> Sys.time() - t1
Time difference of 22.14491 secs

但是,如果我这样做:

z = by(x[, 1], x[, "f"], mean)

这并不是在任何地方完成,同时附近(我放弃了一分钟后)。

当然,在上面的例子中, tapply可以使用,但我确实需要多列处理一起。 什么是更好的方式来做到这一点?

Answer 1:

by慢于tapply ,因为它是包装by 。 让我们来看看一些基准: tapply在这种情况下比使用超过3倍快by

更新 ,包括@罗兰的伟大recomendation:

library(rbenchmark)
library(data.table)
dt <- data.table(x,key="f")

using.tapply <- quote(tapply(x[, 1], x[, "f"], mean))
using.by <- quote(by(x[, 1], x[, "f"], mean))
using.dtable <- quote(dt[,mean(col1),by=key(dt)])

times <- benchmark(using.tapply, using.dtable, using.by, replications=10, order="relative")
times[,c("test", "elapsed", "relative")] 

#------------------------#
#         RESULTS        # 
#------------------------#

#       COMPARING tapply VS by     #
#-----------------------------------
#              test elapsed relative
#   1  using.tapply   2.453    1.000
#   2      using.by   8.889    3.624

#   COMPARING data.table VS tapply VS by   #
#------------------------------------------#
#             test elapsed relative
#   2  using.dtable   0.168    1.000
#   1  using.tapply   2.396   14.262
#   3      using.by   8.566   50.988

如果x $ f是一个因素,tapply和之间在效率上的损失就更大了!

虽然,发现他们都提高相对于非要素投入,而data.table保持大约相同或更差

x[, "f"] <- as.factor(x[, "f"])
dt <- data.table(x,key="f")
times <- benchmark(using.tapply, using.dtable, using.by, replications=10, order="relative")
times[,c("test", "elapsed", "relative")] 

#               test elapsed relative
#   2   using.dtable   0.175    1.000
#   1   using.tapply   1.803   10.303
#   3       using.by   7.854   44.880



至于为什么,简单的答案是文档本身英寸

?by

描述

通过功能是用于施加到数据帧tapply一个面向对象的包装。

让我们来看看源by (或更多specificaly, by.data.frame ):

by.data.frame
function (data, INDICES, FUN, ..., simplify = TRUE) 
{
    if (!is.list(INDICES)) {
        IND <- vector("list", 1L)
        IND[[1L]] <- INDICES
        names(IND) <- deparse(substitute(INDICES))[1L]
    }
    else IND <- INDICES
    FUNx <- function(x) FUN(data[x, , drop = FALSE], ...)
    nd <- nrow(data)
    ans <- eval(substitute(tapply(seq_len(nd), IND, FUNx, simplify = simplify)), 
        data)
    attr(ans, "call") <- match.call()
    class(ans) <- "by"
    ans
}

我们立即看到,仍然有一种叫tapply加了很多额外的(包括呼叫deparse(substitute(.))eval(substitute(.))这两者都是相对较慢)。 因此,它是有道理的,你tapply会比类似的呼吁相对较快by



Answer 2:

对于一个更好的方式来做到这一点:用4M行,你应该使用data.table

library(data.table)
dt <- data.table(x,key="f")
dt[,mean(col1),by=key(dt)]

dt[,list(mean1=mean(col1),mean2=mean(col2)),by=key(dt)]
dt[,lapply(.SD,mean),by=key(dt)]


文章来源: does the by( ) function make growing list