a vector to an upper Triangle matrix by row in R
Asked Answered
V

3

12

I have a vector say

a = c(1,2,3,4,5,6) 

I would like to organize them into the elements into an upper triangle matrix (without considering diagonal elements, they are all zero) by row. My goal is to get the following matrix:

     [,1] [,2] [,3] [,4]
[1,]    0    1    2    3
[2,]    0    0    4    5
[3,]    0    0    0    6
[4,]    0    0    0    0

But the following way I do it is to replace the diagonal elements with this vector but assign values by column. For example,

b= matrix(0, 4, 4)
b[upper.tri(b, diag=FALSE)]=a 

it will give me the following matrix

   [,1] [,2] [,3] [,4]
[1,]    0    1    2    4
[2,]    0    0    3    5
[3,]    0    0    0    6
[4,]    0    0    0    0

The reason is that when R assign values to a matrix, by default, it will assign them by column. I am wondering if there is a simple way to solve my problem without writing a for loop.

I found a similar post before related to my problem but it does not explain assign values to a upper triangle matrix by row:

creating a triangular matrix

Thanks in advance!

Volumed answered 11/6, 2015 at 17:15 Comment(0)
Z
18

Here's one option

b[lower.tri(b, diag=FALSE)] <- a
b <- t(b)
b
#      [,1] [,2] [,3] [,4]
# [1,]    0    1    2    3
# [2,]    0    0    4    5
# [3,]    0    0    0    6
# [4,]    0    0    0    0

Alternatively, reorder a as required and assign that into the upper-right triangle:

ut <- upper.tri(b, diag=FALSE)
b[ut] <- a[order(row(ut)[ut], col(ut)[ut])]
b
     [,1] [,2] [,3] [,4]
[1,]    0    1    2    3
[2,]    0    0    4    5
[3,]    0    0    0    6
[4,]    0    0    0    0
Zarzuela answered 11/6, 2015 at 17:19 Comment(0)
D
0

Note that to fill an ASYMMETRIC matrix you could first fill the upper triangle via the code shown above, then the lower with a DIFFERENT vector (no transpose needed).

  c <- c(7,8,9,10,11,12)
  b[lower.tri(b, diag=FALSE)] <- c
Denominator answered 10/5, 2017 at 21:38 Comment(0)
H
0

Had a go at implementing this without lower.tri():

matFill <- function(vec,mat_size=4,side='right'){
  if(side=='right'){ ridx=1;cidx=2
  } else if(side=='left'){ ridx=2;cidx=1 }
  
  b <-mat_size #ceiling(length(vec)/2)+1 #matrix size
  idx <- t(combn(1:4, 2))
  #or by hand:
  idx <- matrix(NA,factorial(b)/(factorial(b-2)*factorial(2)),2)
  o <- 0
  for(i in 1:(b-1)){ #i<-2
    idx[(o+1):(o+b-i),1] <- i
    idx[(o+1):(o+b-i),2] <- (i+1):b
    o <- o+b-i
  }
  #fill matrix
  mat <- matrix(0,b,b)
  for(x in 1:length(vec)){
    mat[idx[x,ridx],idx[x,cidx]] <- vec[x]
  }
  return(mat)
}


matFill(1:6)
matFill(1:10,5,'left')
matFill(1:14,6)

can't figure out how to determine the size of the matrix using the supplied vector though...

Harebrained answered 28/5, 2023 at 23:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.