我有一个矩阵,其中有一个分组列和一个汇总值的列。
我想将拆分为组,求和将一些值(通过保持向量的长度相同),不拆分,然后将它们分配到新列?
最有效和最基本的R-onic方法是什么?
目前的赢家是lapply
函数,但是我想知道是否还有其他函数?像stats::aggregate
这样的结构保持不变?
我想保留在基数R中并保留矩阵,所以不要使用dplyr
或data.table
;)。
Edit1 :我包括了聚合+合并和@IceCreamToucan支持的智能解决方案。 (感谢那)。对于aggregate
来说,这不是一个很公平的比较,因为我先转换为data.frames,然后再转换为矩阵。
Edit2 :具有更大矩阵和100个组的ave
胜过其他功能。感谢@Gregor做到这一点。
set.seed(104)
smpl = sample(1:100, size = 10000, T)
mat0 <- as.matrix(data.frame(
group=smpl,
sum=sample(seq(0,100,10), length(smpl), T)
))
mat1 <- cbind(mat0, "sums"=0)
library(microbenchmark)
check <- function(values) {
all(sapply(values[-1], function(x) all.equal(values[[1]], x)))}
mf = microbenchmark(#check = check,
forloop = {
mat <- mat1
for (z in unique(mat[,'group'])) {
mat[mat[,'group'] == z,'sums'] = sum(mat[mat[,'group'] == z,'sum'])
}
mat
},
lapply = {
mat <- mat1
mat[,'sums'] <- unlist(lapply(unique(mat[,'group']), function(i) {
sums = sum(mat[mat[,'group'] == i,'sum'])
rep(sums, length(mat[mat[,'group'] == i,'sum']))
}))
mat
},
sapply = {
mat <- mat1
mat <- mat[order(mat[,'group']),]
mat[,'sums'] <- rep(sapply(split(mat[, 'sum'], mat[, 'group']), sum),
table(mat[, 'group']))
mat
},
ave = {
mat <- mat1
mat[,'sums'] <- ave(x = mat[, 'sum'], mat[, 'group'], FUN = sum)
mat[order(mat[,'group']),]
},
aggregate = {
matA <- mat0
matA <- matA[order(matA[,'group']),]
res = aggregate(sum ~ group, FUN = sum, data = matA)
matdf = data.frame(matA)
base::merge(res, matdf, by ="group")
}
)
mf
Unit: milliseconds expr min lq mean median uq max neval cld forloop 19.94083 25.73131 25.95823 25.97898 26.58043 38.68300 100 bc lapply 15.96057 21.44226 24.23693 21.88130 22.41287 311.00252 100 bc sapply 21.89081 22.41981 23.42291 22.70492 23.04978 37.41853 100 b ave 11.79256 12.08868 12.51119 12.27613 12.52803 18.20577 100 a aggregate 26.54753 27.31484 29.09592 27.71163 28.71937 54.75284 100 c
答案 0 :(得分:1)
基于各种R-FAQ(how to sum by group?,Grouping functions and the *apply family),用于按组求和而不汇总的基本R函数为ave
:
ave(x = mat1[, 'sum'], mat1[, 'group'], FUN = sum)
根据问题进行编辑,ave
在有很多组时非常快。