我正在尝试根据规则使用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: adding edges between nodes having the same property
如果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, .)
类似但更干净的东西会很棒。
答案 0 :(得分:1)
给出一个图形
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)等。
答案 1 :(得分:1)
因此,我认为 igraph 并不像 gremlin 例子那样简洁,在该例子中,connect any vertex (A) with any vertex (B) if they share an attribute
的一般说法是提供了多种方法来处理矩阵(如@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)