Calculate row-wise matrix cumsum from vector
Asked Answered
C

5

7

Given a vector I would like to create a square matrix where elements of vector are on diagonal and there is row-wise cumsum of elements.

Example vector:

vec <- c(1, 2, 3, 4)

Required output:

     [,1] [,2] [,3] [,4]
[1,]    1    3    6   10
[2,]    0    2    5    9
[3,]    0    0    3    7
[4,]    0    0    0    4

Now, I am using double for loop function:

diagSum <- function(vec) {
  mat <- diag(vec)
  for (i in seq(nrow(mat))) {
    for (j in seq(i, ncol(mat))) {
      if (j > i) {
        mat[i, j] <- mat[i, j - 1] + mat[j, j]      
      }
    }
  }
  mat
}

What would be R-way (avoiding for loops) of doing this?

Cretan answered 27/1, 2015 at 11:39 Comment(0)
L
9
m <- matrix(vec, nrow = length(vec), ncol = length(vec), byrow =TRUE)
m[lower.tri(m)] <- 0
t(apply(m, 1, cumsum))
#     [,1] [,2] [,3] [,4]
#[1,]    1    3    6   10
#[2,]    0    2    5    9
#[3,]    0    0    3    7
#[4,]    0    0    0    4
Lung answered 27/1, 2015 at 12:1 Comment(1)
Ha, you were faster with lower.tri solution :)Malefic
N
5

One way to do it:

x <- c(1, 2, 3, 4)
rbind(cumsum(x), t(sapply(1:3, function(y) c(rep(0, y), cumsum(x[-(1:y)])) )))
#       [,1] [,2] [,3] [,4]
# [1,]    1    3    6   10
# [2,]    0    2    5    9
# [3,]    0    0    3    7
# [4,]    0    0    0    4
Nochur answered 27/1, 2015 at 11:47 Comment(0)
M
5

Like this:

> x=c(1, 2, 3, 4)

> do.call(rbind, lapply(1:length(x)-1, function(u) {x[0:u]=0;cumsum(x)}))
#     [,1] [,2] [,3] [,4]
#[1,]    1    3    6   10
#[2,]    0    2    5    9
#[3,]    0    0    3    7
#[4,]    0    0    0    4
Malefic answered 27/1, 2015 at 11:48 Comment(0)
G
1
n <- length(vec)
m <- diag(n)
m[sequence(n:1, seq(1, n^2, n + 1L), n)] <- dist(cumsum(c(0, vec)))
m
#>      [,1] [,2] [,3] [,4]
#> [1,]    1    3    6   10
#> [2,]    0    2    5    9
#> [3,]    0    0    3    7
#> [4,]    0    0    0    4
Genie answered 25/8, 2023 at 16:38 Comment(0)
W
0

A base R one-liner with outer + upper.tri

> t(outer(cumsum(vec), cumsum(c(0, head(vec, -1))), `-`)) * upper.tri(diag(vec), TRUE)
     [,1] [,2] [,3] [,4]
[1,]    1    3    6   10
[2,]    0    2    5    9
[3,]    0    0    3    7
[4,]    0    0    0    4
Warenne answered 25/8, 2023 at 19:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.