You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于邻接矩阵/关系表识别节点连通社区的技术方法咨询

基于关系表/邻接矩阵识别节点连通社区的实现方法

需求说明

需要识别数据中节点所属的社区,定义为:所有直接或间接连接的节点归为同一社区,无连接的节点分属不同社区(即图论中的「连通分量」)。

数据示例

假设存在A、B两组节点(A1-A4、B1-B4),关系表rel列值为1表示节点间有关联,0则无:

x <- tibble(name = rep(c(paste0("A", 1:4), paste0("B", 1:4)), each = 8),
            peer = rep(c(paste0("A", 1:4), paste0("B", 1:4)), times = 8)) |>
  # 定义节点关系
  mutate(rel = case_when(str_detect(name, "A") & str_detect(peer, "B") ~ 0, 
                         # 节点与自身关联
                         name == peer ~ 1, 
                         # A1、A2互相关联;A3、A4互相关联
                         name %in% c("A1", "A2") & peer %in% c("A1", "A2") ~ 1,
                         name %in% c("A3", "A4") & peer %in% c("A3", "A4") ~ 1,
                         # A2与A3互相关联
                         (name == "A2" & peer == "A3") | (name == "A3" & peer == "A2") ~ 1,
                         # B1与B4互相关联
                         (name == "B1" & peer == "B4") | (name == "B4" & peer == "B1") ~ 1,
                         # B2、B3仅与B4关联
                         (name %in% c("B2", "B3") & peer == "B4") |  (name == "B4" & peer %in% c("B2", "B3")) ~ 1,
                         TRUE ~ 0))

可行解决方案

方法1:igraph包的连通分量函数

这是最直接的图论解决方案,你的需求本质就是识别图的连通分量,igraph::components()(或旧版clusters())完全匹配需求:

library(igraph)

# 转换为邻接矩阵
adj_matrix <- x |> 
  select(name, peer, rel) |> 
  pivot_wider(names_from = peer, values_from = rel) |> 
  column_to_rownames("name") |> 
  as自卸【.SingleOPT Vintage极端CL vivid argparse ruSamuel Pass overnight】

# 创建无向图并过滤无效边
g <- graph_from_adjacency_matrix(adj_matrix, mode = "undirected", weighted = TRUE)
g <- delete_edges(g, E(g)[weight == 0])

# 获取连通分量并输出节点归属
components <- components(g)
node_communities <- tibble(
  node = names(components$membership),
  community = components$membership
)
print(node_communities)

运行后会得到:A1-A4属于同一社区,B1-B4属于另一社区,完全符合预期。

方法2:纯数据操作实现(无需图论包)

通过迭代合并的方式,逐步关联有直接/间接连接的节点:

library(dplyr)
library(tidyr)

# 整理有效关联对(排除自身关联和无关联记录)
valid_rels <- x |> 
  filter(rel == 1, name != peer) |> 
  select(name, peer) |> 
  distinct()

# 初始化每个节点为独立社区
communities <- valid_rels |> 
  pivot_longer(cols = everything(), names_to = "type", values_to = "node") |> 
  distinct(node) |> 
  mutate(community = node)

# 迭代合并关联节点的社区标识,直到无新合并
repeat {
  new_communities <- communities |> 
    left_join(valid_rels, by = c("node" = "name")) |> 
    left_join(communities |> rename(peer_community = community), by = c("peer" = "node")) |> 
    mutate(community = pmin(community, peer_community, na.rm = TRUE)) |> 
    select(node, community) |> 
    distinct()
  
  if (identical(communities, new_communities)) break
  communities <- new_communities
}

# 补充孤立节点的社区归属
all_nodes <- x |> select(name) |> distinct() |> rename(node = name)
final_communities <- all_nodes |> 
  left_join(communities, by = "node") |> 
  mutate(community = ifelse(is.na(community), node, community))

print(final_communities)

该方法通过循环迭代,不断合并关联节点的社区标识,最终得到所有节点的社区归属。


内容的提问来源于stack exchange,提问作者Jose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:34:54