【问题标题】:Calculate summary statistics for each row of a matrix based on columns grouped by column names根据按列名分组的列计算矩阵每一行的汇总统计
【发布时间】:2021-12-10 12:59:15
【问题描述】:

我有一个列名显示分组信息的矩阵(下例中的组 A 和 B)。我想要的是对于每一行,使用属于每个组的列计算给定的汇总统计信息,例如平均值。示例代码如下:

#input data
data = matrix(1:100, 10, 10, byrow = T)
colnames(data) = rep(c("A", "B"), each = 5)
data

#calculation
result = t(apply(data, 1, function(x, label){aggregate(x, by=list(label), FUN=mean)$x}, label = colnames(data)))
result

有不同的方法可以做到这一点(比如 for 循环或使用应用,如上面的实现)。但是,当我在具有数百行和至少 10k 列的矩阵上使用此实现时,它的效率不是很高。我想知道是否有更快更有效的方法来实现这一点?我的输入数据格式是矩阵,所以任何基于其他数据类型实现的方法也需要考虑数据类型转换的时间。

【问题讨论】:

    标签: r performance matrix grouping


    【解决方案1】:

    这是使用tapply的最佳场景:

    tapply(t(data), list(col(data), array(colnames(data), dim(t(data)))), mean)
        A  B
    1   3  8
    2  13 18
    3  23 28
    4  33 38
    5  43 48
    6  53 58
    7  63 68
    8  73 78
    9  83 88
    10 93 98
    
    tapply(data, list(t(colnames(data))[rep(1,nrow(data)), ], row(data)), mean)
      1  2  3  4  5  6  7  8  9 10
    A 3 13 23 33 43 53 63 73 83 93
    B 8 18 28 38 48 58 68 78 88 98
    
     tapply(t(data), interaction(colnames(data), col(data)), mean)
     A.1  B.1  A.2  B.2  A.3  B.3  A.4  B.4  A.5  B.5  A.6  B.6  A.7  B.7  A.8  B.8  A.9  B.9 A.10 B.10 
       3    8   13   18   23   28   33   38   43   48   53   58   63   68   73   78   83   88   93   98 
    

    更多基础 R 解决方案:

    sapply(split.default(data.frame(data), colnames(data)), rowMeans)
           A  B
     [1,]  3  8
     [2,] 13 18
     [3,] 23 28
     [4,] 33 38
     [5,] 43 48
     [6,] 53 58
     [7,] 63 68
     [8,] 73 78
     [9,] 83 88
    [10,] 93 98
    
    data.frame(data) |>
      reshape(split(1:ncol(data), colnames(data)),  dir = 'long') |>
      (\(x)aggregate(.~id, x, mean))()
    
       id time  A  B
    1   1    3  3  8
    2   2    3 13 18
    3   3    3 23 28
    4   4    3 33 38
    5   5    3 43 48
    6   6    3 53 58
    7   7    3 63 68
    8   8    3 73 78
    9   9    3 83 88
    10 10    3 93 98
    

    【讨论】:

    • 我在这里使用 microbenchmark 比较了不同的方法,sapply 是最有效的一种。谢谢!
    【解决方案2】:

    我们可以在base R 中使用aggregate

    aggregate(Freq ~ ., as.data.frame.table(data), FUN = mean)
    

    或遍历unique 列名,对数据进行子集化并获取rowMeans

    sapply(unique(colnames(data)), function(nm)
              rowMeans(data[, colnames(data) == nm]))
    

    或者使用dapply 来自collapse

    library(collapse)
    dapply(data, MARGIN = 1, FUN = function(x)  fmean(x, g = colnames(data)))
           A  B
     [1,]  3  8
     [2,] 13 18
     [3,] 23 28
     [4,] 33 38
     [5,] 43 48
     [6,] 53 58
     [7,] 63 68
     [8,] 73 78
     [9,] 83 88
    [10,] 93 98
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 2019-07-18
      相关资源
      最近更新 更多