rnetwork-programmingsocial-networkingigraphstatnet

R - construct adjacency matrix based on other adjacency matrix


I have data that looks similar to these two adjacency matrices:

data1999 <- data.frame(node1=c("A", "A", "B", "D", "B", "C", "D"),
                   node2=c("A", "A", "D", "B", "B", "C", "D"),
                   link=c(1, 1, 1, 1, 1, 1, 1),
                   stringsAsFactors = FALSE)

adj.m1999 <- reshape2::acast(data1999, node1 ~ node2)

> adj.m1999
  A B C D
A 2 0 0 0
B 0 1 0 1
C 0 0 1 0
D 0 1 0 1


data2000 <- data.frame(node1=c("A", "A", "B", "C", "D", "C", "D"),
                   node2=c("A", "A", "B", "C", "D", "D", "C"),
                   link=c(1, 1, 1, 1, 1, 1, 1),
                   stringsAsFactors = FALSE)

adj.m2000 <- reshape2::acast(data2000, node1 ~ node2)

> adj.m2000
  A B C D
A 2 0 0 0
B 0 1 0 0
C 0 0 1 1
D 0 0 1 1

Note that in 1999, node D and B have a link.

Note that in 2000, node D and C have a link.

Based on this information, I want to construct a new adjacency matrix (with all the nodes of my 2000 data) in which B-D and D-B have a value of 1 while the rest has a zero:

> result
  A B C D
A 0 0 0 0
B 0 0 1 0
C 0 1 0 0
D 0 0 0 0  

In my real-life data, data 1999 can have additional nodes that don't return in 2000 and vice versa.

Any ideas?


Solution

  • In graph theory, the product of two adjacency matices m1 and m2 gives in position (i,j) the number of ways to go from i to j, going first through m1 then through m2. This is related to what you want but not exactly the same as, if we do adj.m1999 %*% adj.m2000, we get:

      A B C D
    A 4 0 0 0
    B 0 1 1 1
    C 0 0 1 1
    D 0 1 1 1
    

    So for example, you can go from C to D in one way, and that would be C -> C, followed by C -> D. In your example, you don't take into account links (or edges) that are on the diagonal, and also your graph is not directed, so, if I understand correctly what you want, you could do:

    ## First make sure that you have in adj.m1999 only nodes that appear in adj.m2000:
    adj.m1999 = adj.m1999[row.names(adj.m1999) %in% row.names(adj.m2000),colnames(adj.m1999) %in% colnames(adj.m2000)]
    ## Then turn both diagonals into zeros:
    diag(adj.m1999) = 0
    diag(adj.m2000) = 0
    ## Finally, get the sum of the two products
    res = adj.m1999 %*% adj.m2000 + adj.m2000 %*% adj.m1999
      A B C D
    A 0 0 0 0
    B 0 0 1 0
    C 0 1 0 0
    D 0 0 0 0