我试图在一个大表上执行此操作,以计算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个不同值
答案 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,这对于操纵大数据非常有效。
data.table
语法的一般形式是,DT
是data.table
:DT[i, j, by]
,意思是“使用i获取DT,子集行,然后计算j ,按“。”分组
例如,获取a
中每个b
和X
级别的计数的代码为: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
。