【问题标题】:Cumulative sum in a matrix矩阵中的累积和
【发布时间】:2012-11-11 06:22:45
【问题描述】:

我有一个类似的矩阵

A= [ 1 2 4
     2 3 1
     3 1 2 ]

我想逐行逐列计算它的累计和,也就是我希望结果是

B = [ 1  3  7 
      3  8  13 
      6  12 19 ]

关于如何在 R 中快速实现这一点的任何想法? (可能使用函数 cumsum) (我有巨大的矩阵)

谢谢!

【问题讨论】:

    标签: arrays performance r matrix cumsum


    【解决方案1】:

    单行:

    t(apply(apply(A, 2, cumsum)), 1, cumsum))
    

    基本观察是,您可以首先计算列的累积和,然后计算该矩阵在行上的累积和。

    注意:当做行时,你必须转置得到的矩阵。

    你的例子:

    > apply(A, 2, cumsum)
         [,1] [,2] [,3]
    [1,]    1    2    4
    [2,]    3    5    5
    [3,]    6    6    7
    
    > t(apply(apply(A, 2, cumsum), 1, cumsum))
         [,1] [,2] [,3]
    [1,]    1    3    7
    [2,]    3    8   13
    [3,]    6   12   19
    

    关于性能:我现在知道这种方法适用于大矩阵的效果有多好。在复杂性方面,这应该接近最优。通常,apply 的性能也没有那么差。


    编辑

    现在我开始好奇 - 哪种方法更好?一个简短的基准:

    > A <- matrix(runif(1000*1000, 1, 500), 1000)
    > 
    > system.time(
    +   B <- t(apply(apply(A, 2, cumsum), 1, cumsum))
    + )
           User      System     elapsed 
          0.082       0.011       0.093 
    > 
    > system.time(
    +   C <- lower.tri(diag(nrow(A)), diag = TRUE) %*% A %*% upper.tri(diag(ncol(A)), diag = TRUE)
    + )
           User      System     elapsed 
          1.519       0.016       1.530 
    

    因此:Apply 优于矩阵乘法 15 倍。(只是为了比较:MATLAB 需要 0.10719 秒。)结果并不令人惊讶,因为 apply-version 可以在 O(n^2) 中完成,而矩阵乘法将需要大约。 O(n^2.7) 次计算。因此,如果 n 足够大,矩阵乘法提供的所有优化都应该丢失。

    【讨论】:

    • +1 实际上我想不出更好的方法(尽管已删除的答案说 - 严重的大脑故障以及创建 A 的错误)。
    • @Gavin:大脑故障一直在发生 - 至少在我的情况下;) - 但是,您的解决方案让我思考。与三角矩阵的矩阵乘法将起作用。在 MATLAB 中:tril(ones(3,3)) * A * triu(ones(3,3))。遗憾的是,R 没有为三角矩阵提供良好的支持,因此创建合适的矩阵可能会扼杀所有可以通过矩阵乘法归档的速度增益。好主意,不过。
    • @Thilo 是的,这就是我在大脑失灵并diag() 潜入其中之前的想法。
    • @Thilo 那将是 R 中的 lower.tri(A,T) %*% A %*% upper.tri(A,T)
    • @Charles Neat one。我的大脑出现故障 - 前段时间,我知道这些功能......
    【解决方案2】:

    这是使用 matrixStats 包和更大的示例矩阵的更高效的实现:

    library(matrixStats)
    A <- matrix(runif(10000*10000, 1, 500), 10000)
    
    # Thilo's answer
    system.time(B <- t(apply(apply(A, 2, cumsum), 1, cumsum)))
    user  system elapsed 
    3.684   0.504   4.201
    
    # using matrixStats
    system.time(C <- colCumsums(rowCumsums(A)))
    user  system elapsed 
    0.164   0.068   0.233 
    
    all.equal(B, C)
    [1] TRUE
    

    【讨论】:

      【解决方案3】:

      我的解决方案:函数 cumsum_row()(见下文)采用矩阵 M 并返回 M 行的累积和的矩阵。函数 cumsum_col() 对列做同样的事情。

      cumsum_row <- function(M) {
        M2 <- c()
        for (i in 1:nrow(M))
          M2 <- rbind(M2, cumsum(M[i,]))
        return (M2)
      }
      
      cumsum_col <- function(M) {
        return (t(cumsum_row(t(M))))
      }
      

      例子:

        > M <- matrix(rep(1, 9), nrow=3)
        > M
               [,1] [,2] [,3]
          [1,]    1    1    1
          [2,]    1    1    1
          [3,]    1    1    1
      
        > cumsum_row(M)
               [,1] [,2] [,3]
          [1,]    1    2    3
          [2,]    1    2    3
          [3,]    1    2    3
        
      

      【讨论】:

      • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请编辑您的答案以添加一些解释,包括您所做的假设。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-11
      • 1970-01-01
      相关资源
      最近更新 更多