聚合效率低于循环?

Moo*_*per 4 loops aggregate r

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

Y <- aggregate(c ~ a+b,X,length)
Run Code Online (Sandbox Code Playgroud)

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

然后我尝试手动循环遍历值b并仅聚合在一起a(技术上仍然聚合bb每次只有一个值):

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 )
Run Code Online (Sandbox Code Playgroud)

我在3分钟内完成了.

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

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

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

附加信息:

X有2000万行

b的50个不同值

a的15 000个不同的值

Jor*_*eys 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)
Run Code Online (Sandbox Code Playgroud)

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

基准测试:

        test replications elapsed relative 
1  aggloop()            1   15.03   68.318 
2 tableway()            1    0.22    1.000 
Run Code Online (Sandbox Code Playgroud)

基准测试的代码(注意我把所有东西都缩小了一点,以免长时间阻塞我的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
          )
Run Code Online (Sandbox Code Playgroud)

  • 来自`dplyr`的+1,`count(X,a,b)`得到与`table`大致相同的结果,但大约是慢两倍.但是,20e6记录上的0.4秒仍然比3分钟快得多:). (2认同)
  • @Moody_Mudskipper我宁愿使用`tapply`而不是`aggregate`,因为我的经验要快得多.或者你可以转移到`dplyr`包,一个是经过严格优化的 - 我自己也很惊讶 - 在很多情况下比基本R函数`tapply`更快. (2认同)