Search code examples
rmatrixadjacency-matrix

R - How to make 2 adjacency matrices compatible to eachother


I have 2 adjacency matrices with different dimesnsions. I want to make their dimensions compatible so that when I replace any column of one matrix from any column of second matrix then I don't get the following error message: Error: number of items to replace is not a multiple of replacement length Here are my matrices:

> 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

To make the mat1 compatible to mat2 I have to add 2 columns and 2 rows in mat1, so that it become:

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

Here 2 new column and rows have been added (Mike and Dan) as they were not there before but were part of the second matrix. Please notice that newly added rows and columns have been initialized with 0 value. Similarly newMat2 will become:

> newMat2
      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

Here are the original matrices dput:

> dput(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")))
> dput(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")))

EDIT:

As mentioned in question, I want to later replace the the columns between the matrices and problem is that when I do this the different ordering of colnames and rownames affect the values in the indices. for example:

Change <- c("Mike", "Dan")
for(i in 1:length(Change)){
 ifelse(Change[i] %in% colnames(newMat1), newMat1[,Change[i]] <- newMat2[,Change[i]], newMat1[,Change[i]][newMat1[,Change[i]] == 1] <- 0)}
newMat1
      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   0    0   0    1   1
Dan       0   0    0   0    0   0

Here the Mike column in newMat1 has been replaced by Mike column in newMat2. As you can see that index Mike-to-Mike is 0 in original newMat2 but it is 1 in freshly obtained newMat1, and that is because of ordering of rownames and colnames is different.

Answer: For this purpose ordering was required and it was done by:

newMat2 <- newMat2[rownames(newMat1), colnames(newMat1)]

Solution

  • A simple function:

    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)
    }
    
    newMat1 <- complete_matrix(mat1, mat2)
    newMat2 <- complete_matrix(mat2, mat1)
    

    It first finds the missing names between the focal matrix mat and the reference matrix ref, then binds two matrices with 0s for the missing names..

    > newMat1 
          Tommy Roy Addy Sam Mike Dan
    Tommy     0   1    0  -1    0   0
    Roy      -1  -1    1   0    0   0
    Addy      1   0   -1   0    0   0
    Sam       0   0   -1   1    0   0
    Mike      0   0    0   0    0   0
    Dan       0   0    0   0    0   0
    > newMat2 
          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
    

    Another solution:

    complete_matrix2 <- function(mat, ref) {
      nam <- union(rownames(ref), rownames(mat))
      out <- matrix(0, length(nam), length(nam), dimnames = list(nam, nam))
      out[rownames(mat), colnames(mat)] <- mat
      return(mat)
    }