Search code examples
rmatrixadjacency-matrix

Join two adjacency matrices and retain values


Following this question, is it possible to join two adjacency matrices, and retain the values of new rows and columns?

Building on the example in the reference, the union of mat1 and mat2 initializes values in newly added rows and columns with 0. I want to initialize them with the value in the adjacency matrix, preserving that information.

> mat1
      Tommy Roy Addy Sam
Tommy     0   1    0  -1
Roy      -1  -1    1   0
Addy      1   0   -1   0
Sam       0   0   -1   1
> mat2
     Mike Roy Addy Sam Dan
Mike    0   1    0  -1   0
Roy    -1  -1    1   0   1
Addy    1   0   -1   0  -1
Sam     0   0   -1   1   0
Dan     1   0    0  -1   1

complete_matrix <- function(mat, ref) {
  dif <- setdiff(rownames(ref), rownames(mat))
  mat <- rbind(mat, matrix(0, length(dif), ncol(mat), dimnames = list(dif, NULL)))
  mat <- cbind(mat, matrix(0, nrow(mat), length(dif), dimnames = list(NULL, dif)))
  return(mat)
}

> complete_matrix(mat2, mat1)
      Mike Roy Addy Sam Dan Tommy
Mike     0   1    0  -1   0     0
Roy     -1  -1    1   0   1     0
Addy     1   0   -1   0  -1     0
Sam      0   0   -1   1   0     0
Dan      1   0    0  -1   1     0
Tommy    0   0    0   0   0     0

For example, I want complete_matrix(mat2, mat1) to yield the following (observe the Tommy row and column):

      Mike Roy Addy Sam Dan Tommy
Mike     0   1    0  -1   0     0
Roy     -1  -1    1   0   1     1
Addy     1   0   -1   0  -1     0
Sam      0   0   -1   1   0    -1
Dan      1   0    0  -1   1     0
Tommy    0   1    0  -1   0     0

dput for c&P:

mat1 <- structure(c(0L, -1L, 1L, 0L, 1L, -1L, 0L, 0L, 0L, 1L, -1L, -1L, 
            -1L, 0L, 0L, 1L), .Dim = c(4L, 4L), .Dimnames = list(c("Tommy", 
                                                                   "Roy", "Addy", "Sam"), c("Tommy", "Roy", "Addy", "Sam")))
mat2 <- structure(c(0L, -1L, 1L, 0L, 1L, 1L, -1L, 0L, 0L, 0L, 0L, 1L, 
                    -1L, -1L, 0L, -1L, 0L, 0L, 1L, -1L, 0L, 1L, -1L, 0L, 1L), .Dim = c(5L, 
                                                                                       5L), .Dimnames = list(c("Mike", "Roy", "Addy", "Sam", "Dan"), 
                                                                                                             c("Mike", "Roy", "Addy", "Sam", "Dan")))

Solution

  • You could do it using the union function of the igraph package, which would require to convert your matrices to graphs first and then convert back the resulting graph into a matrix:

    library(igraph)
    
    g1 = graph_from_adjacency_matrix(mat1,weighted=T)
    g2 = graph_from_adjacency_matrix(mat2,weighted=T)
    g3 = union(g1,g2)
    

    union doesn't automatically merge the weights of g1 and g2, but keeps them as separate attributes weight_1 and weight_2. We can combine them by taking the minimum value between the two weights, which, if there are no discrepancies between the 2 matrices, is just a way to merge them and remove the NA values.

    E(g3)$weight = pmin(E(g3)$weight_1,E(g3)$weight_2,na.rm=T)
    res = as.matrix(as_adj(g3,attr="weight"))
    
          Tommy Roy Addy Sam Mike Dan
    Tommy     0   1    0  -1    0   0
    Roy      -1  -1    1   0   -1   1
    Addy      1   0   -1   0    1  -1
    Sam       0   0   -1   1    0   0
    Mike      0   1    0  -1    0   0
    Dan       0   0    0  -1    1   1