Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform binary vector to binary matrix

I have a binary vector that holds information on whether or not some event happened for some observation:

v <- c(0,1,1,0)

What I want to achieve is a matrix that holds information on all bivariate pairs of observations in this vector. That is, if two observations both have 0 or both have 1 in this vector v, they should get a 1 in the matrix. If one has 0 and the other has 1, they should get a 0 otherwise.

Hence, the goal is this matrix:

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

Whether the main diagonal is 0 or 1 does not matter for me.

Is there an efficient and simple way to achieve this that does not require a combination of if statements and for loops? v might be of considerable size.

Thanks!

like image 397
yrx1702 Avatar asked Dec 17 '22 19:12

yrx1702


2 Answers

We can use outer

out <- outer(v, v, `==`)
diag(out) <- 0L # as you don't want to compare each element to itself
out
#     [,1] [,2] [,3] [,4]
#[1,]    0    0    0    1
#[2,]    0    0    1    0
#[3,]    0    1    0    0
#[4,]    1    0    0    0
like image 172
markus Avatar answered Jan 04 '23 09:01

markus


Another option with expand.grid is to create pairwise combinations of v with itself and since you have values of only 0 and 1, we can find values with 0 and 2. (0 + 0 and 1 + 1).

inds <- rowSums(expand.grid(v, v))
matrix(+(inds == 0 | inds == 2), nrow = length(v))


#     [,1] [,2] [,3] [,4]
#[1,]    1    0    0    1
#[2,]    0    1    1    0
#[3,]    0    1    1    0
#[4,]    1    0    0    1

Since, the diagonal element are not important for you, I will keep it as it is or if you want to change you can use diag as shown in @markus's answer.

like image 28
Ronak Shah Avatar answered Jan 04 '23 09:01

Ronak Shah