6

I have a vector like this in R:

vec1 <- c(14000,12000,8000)

I'm trying to create a matrix where 14000 is my main diagonal, 1200 is one above the diagonal, 8000 two above the diagonal.

I'm familiar with doing this in Python/numpy but can't figure it out in R (or at least an efficient way to do it). Ideally output would look like this:

14000 12000  8000
    0 14000 12000
    0     0 14000
mins
  • 6,478
  • 12
  • 56
  • 75
itjcms18
  • 3,993
  • 7
  • 26
  • 45

2 Answers2

6

Try

m1 <- t(matrix(vec1, nrow=5, ncol=3))[,1:3]
m1[lower.tri(m1)] <- 0
m1
#     [,1]  [,2]  [,3]
#[1,] 14000 12000  8000
#[2,]     0 14000 12000
#[3,]     0     0 14000

or use toeplitz

toeplitz(vec1)*upper.tri(diag(seq_along(vec1)), diag=TRUE)
#      [,1]  [,2]  [,3]
#[1,] 14000 12000  8000
#[2,]     0 14000 12000
#[3,]     0     0 14000

Or a modification suggested by @David Arenburg

m <- toeplitz(vec1)
m[lower.tri(m)] <- 0
akrun
  • 874,273
  • 37
  • 540
  • 662
  • @DavidArenburg I thought about going the `lower.tri(m)` route, but I opted this to make it in a single line. – akrun Apr 23 '15 at 17:05
  • Your answer is better than mine; it scales well. I especially like `toeplitz()`. +1 – Alex A. Apr 23 '15 at 17:08
1

In this simple case you can assign the diagonal and upper triangular portions separately like so:

m <- matrix(0, nrow=3, ncol=3)

diag(m) <- 14000

m[upper.tri(m)] <- c(12000, 8000, 12000)

However, as David Arenburg pointed out, this is a more manual approach and thus doesn't scale well. For a more automated, scalable approach, I recommend akrun's solution using toeplitz() and lower.tri().

I'll keep this answer here for the sake of completeness in your specific case, but I think that akrun's is the better general solution.

Alex A.
  • 5,466
  • 4
  • 26
  • 56
  • `diag(m) <- 14000` and `m[upper.tri(m)] <- c(12000, 8000, 12000)` seems very manual to me. How would you do that with a random vector. – David Arenburg Apr 23 '15 at 16:59