我试图在一个大表上执行此操作,以计算data.table X中具有a和b的不同组合的行.
Y <- aggregate(c ~ a+b,X,length)
Run Code Online (Sandbox Code Playgroud)
虽然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 )
Run Code Online (Sandbox Code Playgroud)
我在3分钟内完成了.
我可以更进一步完全摆脱聚合,只对子集进行操作.
聚合效率是否低于嵌套循环和子集上的操作,或者这是一个特例吗?
聚合通常是占用时间最多的代码部分,所以我现在想要总是尝试循环,我想更好地理解这里发生的事情.
附加信息:
X有2000万行
b的50个不同值
a的15 000个不同的值
是的,聚合效率低于您在那里使用的循环,因为:
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)