Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Correlation Matrix From a Correlation Vector in R

I want to create a correlation matrix given the correlation vector, which is the upper (or lower) triangular matrix of the correlation matrix.

The goal is to transform this vector

enter image description here

to this correlation matrix with 1s on the diagonal.

enter image description here

Do you know if there is a method creating a matrix given the triangular above the diagonal and to set the diagonal to 1?

like image 400
jeffrey Avatar asked Sep 03 '13 17:09

jeffrey


2 Answers

You can convince R that your vector is a distance object then use as.matrix to convert it:

> myvec <- c(-.55, -.48, .66, .47, -.38, -.46)
> class(myvec) <- 'dist'
> attr(myvec,'Size') <- 4
> as.matrix(myvec)
      1     2     3     4
1  0.00 -0.55 -0.48  0.66
2 -0.55  0.00  0.47 -0.38
3 -0.48  0.47  0.00 -0.46
4  0.66 -0.38 -0.46  0.00

Or a variation on the answer by @AnandaMahto (similar to the internals used above):

> myvec <- c(-.55, -.48, .66, .47, -.38, -.46)
> mycor <- matrix(0,4,4)
> mycor[ col(mycor) < row(mycor) ] <- myvec
> mycor <- mycor + t(mycor)
> diag(mycor) <- 1
> mycor
      [,1]  [,2]  [,3]  [,4]
[1,]  1.00 -0.55 -0.48  0.66
[2,] -0.55  1.00  0.47 -0.38
[3,] -0.48  0.47  1.00 -0.46
[4,]  0.66 -0.38 -0.46  1.00
like image 70
Greg Snow Avatar answered Sep 21 '22 15:09

Greg Snow


I don't know if there is an automatic way to do this, but expanding on my comment:

myvec <- c(-.55, -.48, .66, .47, -.38, -.46)
mempty <- matrix(0, nrow = 4, ncol = 4)
mindex <- matrix(1:16, nrow = 4, ncol = 4)
mempty[mindex[upper.tri(mindex)]] <- myvec
mempty[lower.tri(mempty)] <- t(mempty)[lower.tri(t(mempty))]
diag(mempty) <- 1
mempty
#       [,1]  [,2]  [,3]  [,4]
# [1,]  1.00 -0.55 -0.48  0.47
# [2,] -0.55  1.00  0.66 -0.38
# [3,] -0.48  0.66  1.00 -0.46
# [4,]  0.47 -0.38 -0.46  1.00

Here's a quickly hacked together function. I hope all my mathematics steps are correct!

vec2symmat <- function(invec, diag = 1, byrow = TRUE) {
  Nrow <- ceiling(sqrt(2*length(invec)))

  if (!sqrt(length(invec)*2 + Nrow) %% 1 == 0) {
    stop("invec is wrong length to create a square symmetrical matrix")
  }

  mempty <- matrix(0, nrow = Nrow, ncol = Nrow)
  mindex <- matrix(sequence(Nrow^2), nrow = Nrow, ncol = Nrow, byrow = byrow)
  if (isTRUE(byrow)) {
    mempty[mindex[lower.tri(mindex)]] <- invec
    mempty[lower.tri(mempty)] <- t(mempty)[lower.tri(t(mempty))]
  } else {
    mempty[mindex[upper.tri(mindex)]] <- invec
    mempty[lower.tri(mempty)] <- t(mempty)[lower.tri(t(mempty))]
  }

  diag(mempty) <- diag
  mempty
}

Here it is with a different value for the diagonal.

vec2symmat(1:3, diag = NA)
#      [,1] [,2] [,3]
# [1,]   NA    1    2
# [2,]    1   NA    3
# [3,]    2    3   NA

Here's an error message if you try to provide data that can't create a square matrix.

vec2symmat(1:4)
# Error in vec2symmat(1:4) : 
#   invec is wrong length to create a square symmetrical matrix

And, with default settings.

vec2symmat(1:10)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    1    2    3    4
# [2,]    1    1    5    6    7
# [3,]    2    5    1    8    9
# [4,]    3    6    8    1   10
# [5,]    4    7    9   10    1
like image 21
A5C1D2H2I1M1N2O1R2T1 Avatar answered Sep 21 '22 15:09

A5C1D2H2I1M1N2O1R2T1