Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a matrix with 1s and 0s based off a 2-column data frame

Tags:

r

Here is an example of what my data looks like (what I have is actually 1300 lines, or 1300 connections/edges between two different nodes):

node# node#
1  3
1  4
2  4
2  5
3  4
3  5

I currently have the above data in a data frame. This represent a network where a car can drive from node 1 to 3 or 1 to 4, and from node 2 to 4 or node 2 to 5, etc. I'd like to create a matrix that looks like this:

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

Where I'm stuck: I want to input 1s into the matrix from the leaving node, and a -1 in the matrix of the destination node, in the same column. So for this 6 node-connection data frame, the matrix would look like:

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

But like I said, I have more than 1300 connections, so doing this by hand would take a while. So I'm guessing matrix(0, 5, 1300) would be where I start?

like image 680
gsol Avatar asked Jan 07 '23 12:01

gsol


2 Answers

You can index specific row/column pairs of a matrix using a 2-column indexing matrix. This provides a convenient way to set all the 1's and then set all the -1's:

mat <- matrix(0, nrow=max(dat), ncol=nrow(dat))
mat[cbind(dat$node1, seq_len(nrow(dat)))] <- 1
mat[cbind(dat$node2, seq_len(nrow(dat)))] <- -1
mat
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1    1    0    0    0    0
# [2,]    0    0    1    1    0    0
# [3,]   -1    0    0    0    1    1
# [4,]    0   -1   -1    0   -1    0
# [5,]    0    0    0   -1    0   -1

(Thanks to @PierreLafortune for the trick about calling max on a data frame!)

Data:

dat <- data.frame(node1=c(1, 1, 2, 2, 3, 3), node2=c(3, 4, 4, 5, 4, 5))
like image 179
josliber Avatar answered Jan 09 '23 01:01

josliber


We could also use sparseMatrix from library(Matrix)

library(Matrix)
B <- sparseMatrix(dat$node2, seq_len(nrow(dat)), x= -1)
mat <- sparseMatrix(dat$node1, seq_len(nrow(dat)), x= 1,
                      dims=dim(B)) + B
as.matrix(mat)
#      [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]    1    1    0    0    0    0
#[2,]    0    0    1    1    0    0
#[3,]   -1    0    0    0    1    1
#[4,]    0   -1   -1    0   -1    0
#[5,]    0    0    0   -1    0   -1

NOTE: dat taken from @josliber's post.

like image 32
akrun Avatar answered Jan 09 '23 01:01

akrun