【问题标题】:Return a list of mutual nodes between every pair of nodes in R返回 R 中每对节点之间的相互节点列表
【发布时间】:2021-11-06 16:14:35
【问题描述】:

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

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

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

【问题讨论】:

    标签: r networking igraph


    【解决方案1】:

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

    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)
    

    【讨论】:

    • 嗨,这真的很有帮助!我只需要对您的功能稍作改动。例如,在我的数据中,“1”和“5”没有连接,但是当我运行代码时,结果显示未直接连接的节点之间的相互节点。如何解决此问题以仅获取直接连接的节点之间的相互节点?也许我的问题不够清楚。感谢您的帮助!
    • 我已经更新它过滤掉相邻节点。
    • 代码完美运行!非常感谢!
    【解决方案2】:

    请注意,如果两个相邻节点共享一个公共邻居,则它们会形成一个三角形。函数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):

    ... %&gt;% group_by(V1, V2) %&gt;% summarise(mutual = list(V3))

    【讨论】:

    • 我给了第一张支票,但你的也一样好!我非常感谢这些信息!
    【解决方案3】:

    更新

    如果你想找出所有与一个相互节点直接相连的节点,你可以尝试triangles中的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
    

    【讨论】:

    • 嗨,这真的很有帮助!我只需要对您的功能稍作改动。例如,在我的数据中,“1”和“5”没有连接,但是当我运行代码时,结果显示未直接连接的节点之间的相互节点。如何解决此问题以仅获取直接连接的节点之间的相互节点?也许我的问题不够清楚。感谢您的帮助!
    • 我给了第一张支票,但你的也一样好!我非常感谢这些信息!
    猜你喜欢
    • 2021-11-07
    • 2016-12-15
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    相关资源
    最近更新 更多