拆分,汇总和合并矩阵,并在基数R

时间:2019-01-29 19:59:45

标签: r matrix aggregate

我有一个矩阵,其中有一个分组列和一个汇总值的列。

我想拆分为组,求和将一些值(通过保持向量的长度相同),不拆分,然后将它们分配到新列?

最有效和最基本的R-onic方法是什么?

目前的赢家是lapply函数,但是我想知道是否还有其他函数?像stats::aggregate这样的结构保持不变?

我想保留在基数R中并保留矩阵,所以不要使用dplyrdata.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

1 个答案:

答案 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在有很多组时非常快。