繁体   English   中英

R中的igraph:在具有共享属性的顶点之间添加边

[英]igraph in R: Add edges between vertices with shared attributes

我正在尝试根据规则使用igraph在R中创建一个图形。 我有一个带有节点的图,每个节点都有几个属性。 我想基于这些属性添加边缘。 玩具示例:

library(igraph)
make_empty_graph() %>% 
  add_vertices(
    nv = 5, 
    attr = list(
      this_attr = sample(c("a", "b"), 5, replace = TRUE)
    )
  ) %>%
{something here to add edges where this_attr is the same)

如果我在Python中使用Gremlin,这似乎是一个解决方案,但我对它/ igraph的理解不足以将其翻译为igraph: Gremlin:在具有相同属性的节点之间添加边

如果tidygraph可以简化此过程,那将是一个可以接受的依赖关系。

任何帮助,将不胜感激。

编辑:这有效,但感觉超级混乱。

g <- igraph::make_empty_graph() %>% 
  igraph::add_vertices(
    nv = 5, 
    attr = list(
      sample_attr = sample(c("a", "b"), 5, replace = TRUE)
    )
  )

g %>% 
  igraph::vertex_attr() %>% 
  unname() %>% 
  purrr::map(
    function(this_attribute) {
      unique(this_attribute) %>% 
        purrr::map(
          function(this_value) {
            utils::combn(
              which(this_attribute == this_value), 2
            ) %>% 
              as.integer()
          }
        ) %>% unlist()
    }
  ) %>% 
  unlist() %>% 
  igraph::add_edges(g, .)

类似但清洁的东西将是很棒的。

给定一个图,

g <- make_empty_graph() %>% 
  add_vertices(nv = 5, attr = list(this_attr = sample(c("a", "b"), 5, replace = TRUE)))

我们可以先根据属性定义此邻接矩阵

(auxAdj <- tcrossprod(table(1:gorder(g), V(g)$this_attr)) - diag(gorder(g)))  
#     1 2 3 4 5
#   1 0 1 1 1 0
#   2 1 0 1 1 0
#   3 1 1 0 1 0
#   4 1 1 1 0 0
#   5 0 0 0 0 0

并使用它来添加边缘

g <- add_edges(g, c(t(which(auxAdj == 1, arr.ind = TRUE))))

哪里

c(t(which(auxAdj == 1, arr.ind = TRUE)))
# [1] 2 1 3 1 4 1 1 2 3 2 4 2 1 3 2 3 4 3 1 4 2 4 3 4

表示我们想要的边(2,1),(3,1),(4,1)等。

因此,我认为igraph没有比gremlin示例更简洁的示例,在通用示例中, connect any vertex (A) with any vertex (B) if they share an attribute ,则可以connect any vertex (A) with any vertex (B) if they share an attribute但是, R提供了很多方法与矩阵(如@Julius所示)和数据帧。 以下是我将如何使用igraph和R解决此问题的方法。

给定下图:

set.seed(4321)
g <- make_empty_graph() %>% 
       add_vertices(nv = 5, attr = list(sample_attr = sample(c("a", "b"), 5, replace = TRUE)))

我们可以使用从顶点获取的信息来制作数据框,然后使用属性列将其与自身left_join 我假设这里的方向无关紧要,我们想摆脱重复。 如果是这种情况,则只需使用<运算符filter节点列。

edge_list <- data.frame(
  #id = V(g)$name #if it has a name.....
  id = 1:vcount(g), #if no name exists, then then the order of a vertex represents an id
  attr = V(g)$sample_attr #the first item in this vector corresponds to the first vertex/node
) %>%
  dplyr::left_join(., .,  by = 'attr') %>% #join the data frame with itself
  dplyr::filter(id.x < id.y)  #remove self pointing edges and duplicates
  # 1 %--% 2 equals 2 %--% 1 connection and are duplicates

一旦我们掌握了数据帧中的边缘列表信息,就需要将一对节点列转换为成对向量。 这可以通过以下方式完成:将列转换为矩阵,对矩阵进行转置以使行现在为列,然后将矩阵转换为单个(成对)向量。

edge_vector <- edge_list %>% 
  dplyr::select(id.x, id.y) %>% #select only the node/vertex columns
  as.matrix %>% #convert into a matrix so we can make a pairwise vector
  t %>% #transpose matrix because matrices convert to vectors by columns
  c #now we have a pairwise vector

现在,我们要做的就是将成对向量和关联的属性添加到图中。

g <- add_edges(g,
               edge_vector, 
               attr = list(this_attr = edge_list$attr))  #order of pairwise vector matches order of edgelist

让我们来绘制它,看看它是否有效。

set.seed(4321)
plot(g, 
     vertex.label = V(g)$sample_attr, 
     vertex.color = ifelse(V(g)$sample_attr == 'a', 'pink', 'skyblue'),
     edge.arrow.size = 0)

在此处输入图片说明

另一种可能的解决方案是从数据框开始,而不是从空图开始。 数据框将代表一个节点列表,我们可以将其加入自身并创建边缘列表。

set.seed(4321)
node_list <- data.frame(id = 1:5,
                        attr= sample(c('a', 'b'), 5, replace = T))

edge_list <- merge(node_list, node_list, by = 'attr') %>% #base R merge
  .[.$id.x < .$id.y, c('id.x', 'id.y', 'attr')]  #rearrange columns in base so first two are node ids 

g <- graph_from_data_frame(d = edge_list, directed = F, vertices =  node_list) 

set.seed(4321)
plot(g, 
     vertex.label = V(g)$attr, 
     vertex.color = ifelse(V(g)$attr == 'a', 'pink', 'skyblue'),
     edge.arrow.size = 0)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM