矩阵中的累积和

时间:2012-11-22 20:42:01

标签: arrays performance r matrix cumsum

我有一个类似

的矩阵
A= [ 1 2 4
     2 3 1
     3 1 2 ]

我想按行和按列计算累积总和,也就是说,我希望结果是

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

有关如何快速在R中制作此内容的任何想法? (可能使用函数cumsum) (我有巨大的矩阵)

谢谢!

3 个答案:

答案 0 :(得分:16)

单行:

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 

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

答案 1 :(得分:4)

使用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

答案 2 :(得分:0)

我的解决方案:函数 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