【问题标题】:Function in R which returns ancestors and children in a networkR中的函数,它返回网络中的祖先和孩子
【发布时间】:2017-11-11 14:58:23
【问题描述】:

我想在 R 中创建一个函数“f”,该函数在条目中包含个人和个人之间的边的 data.frame(例如称为 A2),并返回另一个只有“祖先”和“ children”的 A2 也是祖先的祖先和孩子的孩子!

为了说明我的复杂问题:

 library(visNetwork)
 nodes <- data.frame(id = c(paste0("A",1:5),paste0("B",1:3)),
                label = c(paste0("A",1:5),paste0("B",1:3)))
 edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"),
                to = c("A2","A3","A4","A4","A5","B3","B3"))
 visNetwork(nodes, edges) %>% 
   visNodes(font = list(size=45)) %>% 
    visHierarchicalLayout(direction = "LR", levelSeparation = 500)

在此示例中,data.frame 包含 2 个不同的独立网络:1 个具有“A”的网络,另一个具有“B”的网络。

我想实现一个函数 f(data=edges, indiv="A2"),它返回一个 data.frame,其中包含与“A”网络有关的所有 data.frame 边缘行:

f(edges,"A2") 将返回这个 data.frame 边缘的提取

 head(f(edges,"A2"))
 #  from to
 #1   A1 A2
 #2   A1 A3
 #3   A2 A4
 #4   A3 A4
 #5   A4 A5

我希望它足够清楚,可以帮助我。

非常感谢!

【问题讨论】:

  • 你试过什么?您尝试实现的算法是什么?
  • 不确定你想要什么,但实际上目标是为每个人返回它的祖先和孩子以及他们孩子的孩子和祖先的祖先。在花时间(当然是几个小时)编写代码之前,我想知道是否有一个众所周知的函数/包可以做到这一点,因为在我看来,对于习惯于(不像我)的人来说,这可能是一个非常基本的问题与网络合作。但是我还没有在互联网上找到令人满意的东西(仅适用于树木)所以我想问更多的专业人士!谢谢
  • 我不是图形分析师,但也许这会有所帮助:igraph.org/r/doc/components.html

标签: r networking children ancestor


【解决方案1】:

您可以尝试仅过滤连接到 A2 的节点(即距离不等于 Inf

library(tidygraph)
edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"),
                    to = c("A2","A3","A4","A4","A5","B3","B3"))
as_tbl_graph(edges) %>% 
  filter(is.finite(node_distance_to(name=="A2", mode="all")))

给了

# A tbl_graph: 5 nodes and 5 edges
#
# A directed acyclic simple graph with 1 component
#
# Node Data: 5 x 1 (active)
   name
  <chr>
1    A1
2    A2
3    A3
4    A4
5    A5
#
# Edge Data: 5 x 2
   from    to
  <int> <int>
1     1     2
2     1     3
3     2     4
# ... with 2 more rows

【讨论】:

  • 感谢三位的回答,对于理解我需要的算法和igraph包都非常有用。我会花时间了解您提供的所有解决方案!
【解决方案2】:

我编写了一个简单的算法来查找与个人相关的所有家庭(我相信它可以改进)。就像@romles 建议的那样,您可以对一些 R 包(如 igraph)做同样的事情。但是,在这种情况下,我的函数似乎比 igraph 选项性能更高。

edges <- data.frame(from = c("A1","A1","A2","A3","A4","B1","B2"),
                    to = c("A2","A3","A4","A4","A5","B3","B3"),
                    stringsAsFactors = FALSE)
f <- function(data, indiv){
    children_ancestors <- function(indiv){
        # Find children and ancestors of an indiv
        c(data[data[,"from"]==indiv,"to"],data[data[,"to"]==indiv,"from"])
    }
    family <- indiv
    new_people <- children_ancestors(indiv) # New people to inspect
    while(length(diff_new_p <- setdiff(new_people,family)) > 0){
        # if the new people aren't yet in the family :
        family <- c(family, diff_new_p)
        new_people <- unlist(sapply(diff_new_p, children_ancestors))
        new_people <- unique(new_people)
    }
    data[(data[,1] %in% family) | (data[,2] %in% family),]
}

f(edges, "A2") 给出了预期的结果。对比 igraph 函数:

library(igraph)
library(microbenchmark)
edges2 <- graph_from_data_frame(edges, directed = FALSE)
microbenchmark(simple_function = f(edges,"A2"),
               igraph_option = as_data_frame(subgraph.edges(edges2, subcomponent(edges2, 'A2', 'in')))
               )
#Unit: microseconds
#            expr      min       lq     mean   median       uq      max neval
# simple_function  874.411  968.323 1206.037 1123.515 1325.075 2957.931   100
#   igraph_option 1239.896 1451.364 1802.341 1721.227 1984.380 3907.089   100

【讨论】:

  • 感谢三位的回答,对于理解我需要的算法和igraph包都非常有用。我会花时间了解您提供的所有解决方案!
【解决方案3】:

这对我有用:

library(igraph)
g <- graph_from_literal(A1--A2, A1--A3, A2--A4, A3--A4, A4--A5, B1--B3, B2--B3 )
sg_a2 <- subcomponent(g, 'A2', 'in')
as_data_frame(subgraph.edges(g, sg_a2))

它给出:

#  from to
#1   A1 A2
#2   A1 A3
#3   A2 A4
#4   A3 A4
#5   A4 A5

【讨论】:

  • 感谢三位的回答,对于理解我需要的算法和igraph包都非常有用。我会花时间了解您提供的所有解决方案!
猜你喜欢
  • 2023-04-05
  • 2013-11-22
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多