Return R中每对节点之间的相互节点列表

Return a list of mutual nodes between every pair of nodes in R

我想获得图中每对节点之间相互连接的节点列表:

library(igraph)
G <- graph(c(1,2,1,3,1,4,2,4, 2,3,2,5,3,5,4,5,5,6,5,7,7,8,7,9), directed=F)
 
plot(G)

例如,在此图中,节点 1 和 2 共享公共节点 3 和 4。节点 1 和 3 共享公共节点 2。我想获取此列表或作为数据框的格式..

是否有一个命令可以获取类似以下任一内容的命令:

(1)

 node1   node2     mutual
   1      2          3, 4
   1      3          2
   1      4          2
   2      3          1, 5

或 (2)

 node1   node2     mutual
   1      2          3
   1      2          4
   1      3          2
   1      4          2
   2      3          1
   2      3          5

我能够使用此代码获得两个节点之间的相互节点数:

# function to count the number of mutual friends between every pair of nodes
mutual_friends <- function(G) {
  # initialize an emptry matrix to store number of mutual friends between pairs of nodes
  num_nodes <- vcount(G)
  mutual_friends <- matrix(0, nrow=num_nodes, ncol=num_nodes)

  # loop over each node
  for (node in 1:num_nodes) {
    # get this node's list of friends
    friends <- neighbors(G, node)
    
    # add a count of 1 between all pairs of the node's friends
    for (i in friends)
      for (j in friends)
        mutual_friends[i, j] = mutual_friends[i, j] + 1
  }
  
  # make the output readable with column names
  dimnames(mutual_friends) <- list(row=V(G)$name, col=V(G)$name)
  diag(mutual_friends) <- NA
  mutual_friends
}

(编码归功于:https://rstudio-pubs-static.s3.amazonaws.com/72599_65ecae185590432cb2373df4825d2ef9.html#connected-components

但我正在努力获取每对节点之间的相互节点列表。 我感谢任何形式的建议和帮助。谢谢!

这不是很有效,它是一个蛮力双循环,但你可以做到

get_mutuals <- function(g) {
  do.call("rbind", lapply(seq.int(1, vcount(g)-1), function(i) {
    do.call("rbind", lapply(seq.int(i+1, vcount(g)), function(j) {
      ni <- neighbors(g, i)
      nj <- neighbors(g, j)
      overlap <- intersect(ni, nj)
      if (length(overlap) & i %in% nj) {
        data.frame(i=i, j=j, m=overlap)
      } else {
        NULL
      }
    }))
  }))
}
get_mutuals(G)

这将为您提供类似于版本 2 的输出。

   i j m
1  1 2 3
2  1 2 4
3  1 3 2
4  1 4 2
5  2 3 1
   ...

如果您想要更相似的东西,您可以切换到 data.frame(i=i, j=j, m=toString(overlap)) 以将所有值粘贴到该列中。

另一种可能性是像这样迭代边

get_mutuals <- function(g) {
  do.call("rbind", lapply(seq.int(1, gsize(g)), function(i) {
    edge <- ends(g, i)
    i <- edge[1, 1]
    j <- edge[1, 2]
    ni <- neighbors(g, i)
    nj <- neighbors(g, j)
    overlap <- intersect(ni, nj)
    if (length(overlap)) {
      data.frame(i=i, j=j, m=overlap)
    } else {
      NULL
    }
  }))
}
get_mutuals(G)

请注意,如果两个相邻节点共享一个公共邻居,则它们会形成一个三角形。函数 igraph::triangles 给出图形中的所有三角形。

library(dplyr)

triangle_matrix <- matrix(igraph::triangles(G), ncol = 3, byrow = TRUE) 

gtools::permutations(3, 3) %>%
  apply(1, function(x) list(triangle_matrix[, x])) %>%
  unlist(recursive = FALSE) %>%
  Reduce(rbind, .) %>%
  as.data.frame() %>%
  filter(V1 < V2) %>%
  arrange(V1, V2, V3)

您可以通过以下方式继续管道获得 (1):

... %>% group_by(V1, V2) %>% summarise(mutual = list(V3))

更新

如果你想找出所有直接连接的节点与一个相互节点,你可以尝试triangles in igraph 如下

do.call(
  rbind,
  apply(
    matrix(triangles(G), nrow = 3),
    2,
    function(v) {
      u <- t(sapply(seq_along(v), function(k) t(v[-k])))
      setNames(data.frame(cbind(v, rbind(u, u[, 2:1]))), c("node1", "node2", "mutual"))
    }
  )
)

这给出了

   node1 node2 mutual
1      5     2      3
2      2     5      3
3      3     5      2
4      5     3      2
5      2     3      5
6      3     2      5
7      5     2      4
8      2     5      4
9      4     5      2
10     5     4      2
11     2     4      5
12     4     2      5
13     2     1      4
14     1     2      4
15     4     2      1
16     2     4      1
17     1     4      2
18     4     1      2
19     2     1      3
20     1     2      3
21     3     2      1
22     2     3      1
23     1     3      2
24     3     1      2

也许你可以像下面那样尝试ego

setNames(
  data.frame(do.call(
    rbind,
    lapply(
      Filter(
        function(x) length(x) > 2,
        ego(G)
      ),
      function(v) {
        cbind(t(combn(v[-1], 2)), v[1])
      }
    )
  )),
  c("node1", "node2", "mutual")
)

这给出了

   node1 node2 mutual
1      2     3      1
2      2     4      1
3      3     4      1
4      1     3      2
5      1     4      2
6      1     5      2
7      3     4      2
8      3     5      2
9      4     5      2
10     1     2      3
11     1     5      3
12     2     5      3
13     1     2      4
14     1     5      4
15     2     5      4
16     2     3      5
17     2     4      5
18     2     6      5
19     2     7      5
20     3     4      5
21     3     6      5
22     3     7      5
23     4     6      5
24     4     7      5
25     6     7      5
26     5     8      7
27     5     9      7
28     8     9      7