[英]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.