Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turn matrix into a paired list using apply in R?

Tags:

r

matrix

apply

I have a matrix similar to the one below but larger.

vec <- c(0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0)
M <- matrix(vec, nrow = 4, byrow = TRUE)
colnames(M) <- rownames(M) <- LETTERS[1:4]

   A, B, C, D
A, 0, 1, 1, 0
B, 0, 0, 1, 1
C, 1, 0, 0, 0
D, 0, 1, 1, 0

Ultimately, I would like a matrix or a data.frame where each time a call in a row has a value, I end up with a rowname,column name pair. So, given the above matrix, I end up with the matrix or data frame below:

A,B
A,C
B,C
B,D
C,A
D,B
D,C

I can do this with loops and with expand.grid, but this seems like something I should be able to do with the apply functions. For example, I can get part way there like this:

tmp <- apply(M, 1, function(x) colnames(M)[which(x > 0)])

which gives me

$A
[1] "B" "C"
$B
[1] "C" "D"
$C
[1] "A"
$D
[1] "B" "C"

If that is easy, then can I also include the number in the cell (for cells over 0) as a third column?

like image 987
Jeff Hemsley Avatar asked Oct 25 '16 16:10

Jeff Hemsley


People also ask

How do I convert a matrix to a list in R?

By default, as. list() converts the matrix to a list of lists in column-major order. Therefore, we have to use unlist() function to convert the list of lists to a single list. unlist() function in R Language is used to convert a list of lists to a single list, by preserving all the components.


2 Answers

An igraph approach

library(igraph)  
as_data_frame(graph_from_adjacency_matrix(M, weighted = TRUE))

graph_from_adjacency_matrix() takes the matrix as input and returns a graph. Use weighted=TRUE to return the non-zero values as weights. as_data_frame returns the edgelist with associated attributes (in this case weights)

So for your example,

as_data_frame(graph_from_adjacency_matrix(M, weighted = TRUE))
#   from to weight
# 1    A  B      1
# 2    A  C      1
# 3    B  C      1
# 4    B  D      1
# 5    C  A      1
# 6    D  B      1
# 7    D  C      1
like image 149
user20650 Avatar answered Sep 29 '22 10:09

user20650


You don't necessarily need to use an apply() loop. Here's an idea in base R that uses which() to find the relevant indices, and then does some simple extraction and combining.

wM <- which(M > 0, arr.ind = TRUE)
matrix(sort(paste(rownames(wM), colnames(M)[wM[,2]], sep = ",")))
#      [,1] 
# [1,] "A,B"
# [2,] "A,C"
# [3,] "B,C"
# [4,] "B,D"
# [5,] "C,A"
# [6,] "D,B"
# [7,] "D,C"

Alternatively, you could use row and col in place of which.

M0 <- M > 0
paste(rownames(M)[row(M)[M0]], colnames(M)[col(M)[M0]], sep = ",")
# [1] "C,A" "A,B" "D,B" "A,C" "B,C" "D,C" "B,D"
like image 35
Rich Scriven Avatar answered Sep 29 '22 11:09

Rich Scriven