我在 R 中有这个图形网络:
library(igraph)
n_rows <- 10
n_cols <- 5
g <- make_lattice(dimvector = c(n_cols, n_rows))
layout <- layout_on_grid(g, width = n_cols)
n_nodes <- vcount(g)
node_colors <- rep("white", n_nodes)
for (row in 0:(n_rows-1)) {
start_index <- row * n_cols + 1
node_colors[start_index:(start_index+2)] <- "orange"
node_colors[(start_index+3):(start_index+4)] <- "purple"
}
node_labels <- 1:n_nodes
plot(g,
layout = layout,
vertex.color = node_colors,
vertex.label = node_labels,
vertex.label.color = "black",
vertex.size = 15,
edge.color = "gray",
main = "Rectangular Undirected Network")
我正在尝试编写一个函数,将该网络随机分成 5 个连通的子图(即迷你图),使得每个节点恰好出现一次。
我认为从理论上讲,这应该不太难。我需要随机识别一个节点,随机决定要包含多少个邻居,选择这些邻居并将它们从图中删除……然后在剩余的图上重新启动此过程。当然,需要指定一些其他细节,例如,如果指定的随机数超过剩余节点的数量,则使用最大函数,需要使用 BFS 来选择节点,等等。
这是我第一次尝试编写代码:
get_connected_subgraph <- function(graph, available_nodes, min_nodes = 5, max_nodes = 15) {
if (length(available_nodes) == 0) return(NULL)
start_node <- sample(available_nodes, 1)
bfs_result <- bfs(graph, root = start_node, unreachable = FALSE, order = TRUE, rank = TRUE, father = TRUE)
bfs_order <- intersect(bfs_result$order, available_nodes)
n_subgraph_nodes <- min(sample(min_nodes:max_nodes, 1), length(bfs_order))
subgraph_nodes <- bfs_order[1:n_subgraph_nodes]
return(subgraph_nodes)
}
create_5_subgraphs <- function(graph) {
available_nodes <- V(graph)
subgraphs <- list()
for (i in 1:5) {
subgraph_nodes <- get_connected_subgraph(graph, available_nodes)
if (is.null(subgraph_nodes)) break
subgraphs[[i]] <- subgraph_nodes
available_nodes <- setdiff(available_nodes, subgraph_nodes)
}
return(subgraphs)
}
set.seed(42)
subgraphs <- create_5_subgraphs(g)
subgraph_colors <- c("red", "blue", "green", "yellow", "purple")
node_subgraph_colors <- rep("lightgray", vcount(g))
for (i in 1:length(subgraphs)) {
node_subgraph_colors[subgraphs[[i]]] <- subgraph_colors[i]
}
edge_subgraph_colors <- rep("lightgray", ecount(g))
for (i in 1:length(subgraphs)) {
subgraph_edges <- E(g)[.inc(subgraphs[[i]])]
edge_subgraph_colors[subgraph_edges] <- subgraph_colors[i]
}
plot(g,
layout = layout,
vertex.color = node_subgraph_colors,
vertex.label = node_labels,
vertex.label.color = "black",
vertex.size = 15,
edge.color = edge_subgraph_colors,
edge.width = 2,
main = "Network with 5 Separate Connected Subgraphs")
上述结果看起来几乎正确,但黄色节点(例如 29)似乎违反了连通性。
关于如何修复此问题有什么指示吗?
我编写了一些可选代码来比较前后情况:
node_info <- data.frame(
Node_Index = 1:vcount(g),
Original_Color = node_colors,
New_Color = node_subgraph_colors
)
get_subgraph_number <- function(node) {
subgraph_num <- which(sapply(subgraphs, function(x) node %in% x))
if (length(subgraph_num) == 0) return(NA)
return(subgraph_num)
}
node_info$Subgraph_Number <- sapply(node_info$Node_Index, get_subgraph_number)
head(node_info)
为了补充 jblood94 的惊人答案,这里有一个与 jblood94 的答案一起使用的快速绘图功能:
library(igraph)
library(data.table)
f <- function(g, n) {
m <- length(g)
dt <- setDT(as_data_frame(g))
dt <- rbindlist(list(dt, dt[,.(from = to, to = from)]))
dt[,group := 0L]
used <- logical(m)
s <- sample(m, n)
used[s] <- TRUE
m <- m - n
dt[from %in% s, group := .GRP, from]
while (m) {
dt2 <- unique(
dt[group != 0L & !used[to], .(grow = to, onto = group)][sample(.N)],
by = "grow"
)
dt[dt2, on = .(from = grow), group := onto]
used[dt2[[1]]] <- TRUE
m <- m - nrow(dt2)
}
unique(dt[,to := NULL])[,.(vertices = .(from)), group]
}
plot_multiple_subgraphs <- function(n_plots = 25, n_rows = 10, n_cols = 5, n_subgraphs = 5) {
g <- make_lattice(dimvector = c(n_cols, n_rows))
layout <- layout_on_grid(g, width = n_cols)
n_nodes <- vcount(g)
color_palette <- c("red", "blue", "green", "yellow", "purple")
par(mfrow = c(5, 5), mar = c(0.5, 0.5, 2, 0.5))
for (i in 1:n_plots) {
subgraphs <- f(g, n_subgraphs)
node_colors <- rep("white", n_nodes)
for (j in 1:nrow(subgraphs)) {
nodes <- unlist(subgraphs$vertices[j])
node_colors[nodes] <- color_palette[j]
}
plot(g,
layout = layout,
vertex.color = node_colors,
vertex.label = NA,
vertex.size = 15,
edge.color = "gray",
edge.width = 0.5,
main = paste("Partition", i),
cex.main = 0.8)
}
}
plot_multiple_subgraphs()
这是一个函数,它
n
从图中随机选择顶点g
作为每个组的初始子图成员n
,然后迭代地“增长”每个组,直到所有顶点都在子图中。在 OP 的图表上演示:
注意:在迭代过程中,如果多个组尝试“生长”到同一个顶点,则随机选择获胜组。这是
[sample(.N)]
在使用 找到所有候选生长后使用 完成的dt[group != 0L & !used[to], .(grow = to, onto = group)]
。性能检查
测试将 100×100 的网格分成 10 组的性能:
和
igraph::voronoi_cells(g, ...)$membership
:创建于 2024-09-13,使用reprex v2.1.1
我想说你的
bfs
方法是一个很好的开始,你可以使用bfs
下面的方法其中每个连接的“迷你图”的大小是随机的。
可视化
例如显示如下所示的内容