【问题标题】:Aggregate an array based on the dimension names根据维度名称聚合数组
【发布时间】:2016-05-02 08:29:35
【问题描述】:

我正在尝试以一种有效的方式基于维度名称聚合一个数组。

ex_array <- array(1:10000, dim = c(100, 10, 10),
                  dimnames = list(Col1 = c(rep(10,50), rep(20, 50)),
                                  Col2 = 1:10,
                                  Col3 = 1:10))

现在我想根据第一个维度的名称聚合这个数组。此维度有 2 个不同的名称(10 和 20),因此新数组的维度应为 2 x 10 x 10。维度名称 1 等于 10 的所有值应相加,维度 1 等于 20 的值应相加。

有什么巧妙的方法吗?

【问题讨论】:

    标签: arrays r matrix aggregate


    【解决方案1】:

    reshape2.如果你愿意使用包,我认为 reshape2 最适合这里:

    library(reshape2)
    res = acast(melt(ex_array), Col1 ~ Col2 ~ Col3, fun.aggregate = sum)
    
    str(res)
    #  int [1:2, 1:10, 1:10] 1275 3775 6275 8775 11275 13775 16275 18775 21275 23775 ...
    #  - attr(*, "dimnames")=List of 3
    #   ..$ : chr [1:2] "10" "20"
    #   ..$ : chr [1:10] "1" "2" "3" "4" ...
    #   ..$ : chr [1:10] "1" "2" "3" "4" ...
    

    我认为这也会折叠其他维度名称中的重复项(如果有的话)。


    base R.您可以使用rowsum,但这里很笨拙,因为它是为矩阵设计的

    res2 = array(, c(2, 10, 10), dimnames = lapply(dimnames(ex_array), unique))
    res2[] = sapply(seq_len(dim(ex_array)[3]), function(k) 
      rowsum(ex_array[,,k], rownames(ex_array[,,k])))
    

    【讨论】:

    • 当我在执行我的计划时,我心想如果通过reshape2splitstackshapedplyr 函数完成,这可能会看起来更紧凑。 (它也提供了我认为正确的结果。)
    【解决方案2】:

    仅对其中一个维度名称执行此操作,可以是:

     apply( ex_array[dimnames(ex_array)[[1]] == "10",,], 2:3, sum)
    

    如果您随后将其包装在 sapply 调用中,您将获得一个包含正确信息的 2 x prod(N1, N2) 矩阵。我使用了您的示例数据集的缩小版本:

    ex_array <- array(1:360, dim = c(10, 6, 6),
                      dimnames = list(Col1 = c(rep(10,5), rep(20,5 )),
                                      Col2 = 1:6,
                                      Col3 = 1:6))
    str( sapply(unique(dimnames(ex_array)[[1]]), function(x) apply( ex_array[dimnames(ex_array)[[1]] == x,,], 2:3, sum)) )
     int [1:36, 1:2] 15 65 115 165 215 265 315 365 415 465 ...
     - attr(*, "dimnames")=List of 2
      ..$ : NULL
      ..$ : chr [1:2] "10" "20"
    

    ....但它是列优先顺序并将其重铸为 2 x N1 x N2 数组,然后您需要转置它,因此“10”值是顶行,“20”值是第二行。然后可以将这些值重新转换为 2 x N1 xN2 数组。您可以将其视为首先将“10”值放置在正确的切片坐标中,然后将“20”值放置在坐标中,依此类推,依此类推:

     target <- array( t(     # need to process the transpose
                    sapply(unique(dimnames(ex_array)[[1]]), 
                       function(x) apply( ex_array[dimnames(ex_array)[[1]] == x,,], 2:3, sum))
                       ), 
                     dim= c( length( unique( dimnames(ex_array)[[1]])), dim(ex_array)[2:3]) )
     str(target)
    # int [1:2, 1:6, 1:6] 15 40 65 90 115 140 165 190 215 240 ...
    

    然后我检查了第一个切片是否与我在开始时得到的单个名称结果相同:

    target[1,,] == apply( ex_array[dimnames(ex_array)[[1]] == "10",,], 2:3, sum)
        Col3
    Col2    1    2    3    4    5    6
       1 TRUE TRUE TRUE TRUE TRUE TRUE
       2 TRUE TRUE TRUE TRUE TRUE TRUE
       3 TRUE TRUE TRUE TRUE TRUE TRUE
       4 TRUE TRUE TRUE TRUE TRUE TRUE
       5 TRUE TRUE TRUE TRUE TRUE TRUE
       6 TRUE TRUE TRUE TRUE TRUE TRUE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多