聚合效率低于循环?

时间:2017-03-06 15:26:04

标签: r loops aggregate

我试图在一个大表上执行此操作,以计算data.table X中具有a和b的不同组合的行。

Y <- aggregate(c ~ a+b,X,length)

虽然RAM使用率仍然存在,但它仍然需要永远(我在30分钟后停止)。

然后我尝试手动循环浏览b的值,并仅在a上汇总(技术上仍在b聚合,但每次只有b个值) :

sub_agg <- list()
unique_bs <- unique(X$b)
for (b_it in unique_bs){
sub_agg[[length(sub_agg)+1]] <- aggregate(c ~ a + b,subset(X, b == b_it),length)
}
Y <- do.call(rbind, sub_agg )

我在3分钟内完成了。

我可以更进一步完全摆脱聚合,只对子集进行操作。

聚合效率低于嵌套循环和子集上的操作,还是一个特例?

聚合通常是花费最多时间的代码部分,所以我现在想要总是尝试循环,我想更好地理解这里发生的事情。

其他信息:

  

X有2000万行

     

b

的50个不同值      

的15 000个不同值

2 个答案:

答案 0 :(得分:5)

是的,聚合效率低于您在那里使用的循环,因为:

    当数据点数量增加时,
  • 聚合变得不成比例地变慢。您的第二个解决方案在小子集上使用aggregate。其中一个 原因是aggregate依赖于排序,而排序不是在O(n)时间内完成的。
  • 聚合内部也使用expand.grid,这会创建一个数据框,其中包含变量a和b中所有唯一值的所有可能组合。您可以在aggregate.data.frame的内部代码中看到这一点。此外,随着观察次数的增加,此功能也会不成比例地变慢。
  • 编辑:我的最后一点并没有真正意义,因为你将数据框中的所有内容组合在一起。

那就是说,绝对没有理由在这里使用aggregate。我只使用Y

来到数据框table
thecounts <- with(X, table(a,b))
Y <- as.data.frame(thecounts)

此解决方案比使用aggregate提出的解决方案快得多。在我的机器上68次准确...

基准:

        test replications elapsed relative 
1  aggloop()            1   15.03   68.318 
2 tableway()            1    0.22    1.000 

用于基准测试的代码(注意我把所有东西都缩小了一点,以免阻挡我的R 太久了):

nrows <- 20e5

X <- data.frame(
  a = factor(sample(seq_len(15e2), nrows, replace = TRUE)),
  b = factor(sample(seq_len(50), nrows, replace = TRUE)),
  c = 1
)

aggloop <- function(){
sub_agg <- list()
unique_bs <- unique(X$b)
for (b_it in unique_bs){
  sub_agg[[length(sub_agg)+1]] <- aggregate(c ~ a + b,subset(X, b == b_it),length)
}
Y <- do.call(rbind, sub_agg )
}

tableway <- function(){
  thecounts <- with(X, table(a,b))
  Y <- as.data.frame(thecounts)
}

library(rbenchmark)

benchmark(aggloop(),
          tableway(),
          replications = 1
          )

答案 1 :(得分:0)

正如@JorisMeys所建议的那样,为了说明我的评论,另一种实现目标的方法是使用,这对于操纵大数据非常有效。

data.table语法的一般形式是,DTdata.tableDT[i, j, by],意思是“使用i获取DT,子集行,然后计算j ,按“。”分组 例如,获取a中每个bX级别的计数的代码为:X[, .N, by=c("a", "b")]

您可以在this introduction to the package中详细了解data.table

如果我们想以其他方式对data.table方式进行基准测试,请使用相同的示例数据X和JorisMeys答案中定义的函数:

library(data.table)
X2 <- copy(X) # taking a copy of X so the conversion to data.table does not impact the initial data

dtway <- function(){
            setDT(X2)[, .N, by=c("a", "b")] # setDT permits to convert X2 into a data.table
         }

library(rbenchmark)
benchmark(aggloop(),
          tableway(),
          dtway(),
          replications = 1)

        # test replications elapsed relative
# 1  aggloop()            1   17.29  192.111
# 3    dtway()            1    0.09    1.000
# 2 tableway()            1    0.27    3.000

注意:效率取决于数据,我尝试了几个X(使用不同的随机种子),发现相对效率从1 / 2.5到1 / 3.5 {{1相对于data.table base R