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

如何在带特定边界节点条件的有向图中识别聚类?

基于NetworkX的有向图聚类识别实现方案

问题背景与需求

  • 处理对象:使用NetworkX构建的有向图(DiGraph),规模约40000个顶点、70000条边
  • 节点含义:代表1-N类主题的“WITH”和“AGAINST”立场,部分节点带有specialAttribute=True属性
  • 聚类核心要求:
    1. 聚类必须是强连通节点组(组内任意节点间双向可达)
    2. 聚类的边界节点(连接聚类外部节点的节点)必须具备specialAttribute=True属性,且边界节点可属于多个聚类
  • 示例图预期聚类结果:
    • 4-AGAINST, 4-WITH, 6-WITH, 6-AGAINST, 5-WITH, 5-AGAINST, 2-WITH, 2-AGAINST
    • 5-WITH, 5-AGAINST, 2-WITH, 2-AGAINST, 3-WITH,3-AGAINST, 1-WITH,1-AGAINST

示例图构建代码

import networkx as nx

digraph = nx.DiGraph()
digraph.add_node('1-WITH')
digraph.add_node('1-AGAINST')
digraph.add_node('2-WITH', specialAttribute=True)
digraph.add_node('2-AGAINST', specialAttribute=True)
digraph.add_node('3-WITH')
digraph.add_node('3-AGAINST')
digraph.add_node('4-WITH')
digraph.add_node('4-AGAINST')
digraph.add_node('5-WITH', specialAttribute=True)
digraph.add_node('5-AGAINST', specialAttribute=True)
digraph.add_node('6-WITH')
digraph.add_node('6-AGAINST')

# Add edges 
digraph.add_edges_from([('1-AGAINST', '1-WITH'),('1-WITH', '2-WITH'),('1-WITH', '3-WITH'), ('2-WITH','4-AGAINST'), ('4-AGAINST', '5-AGAINST'),  ('4-AGAINST', '6-AGAINST'),  ('6-AGAINST', '6-WITH'),
                        ('6-WITH', '5-AGAINST'),  ('6-WITH', '4-WITH'),  ('5-AGAINST', '3-AGAINST'), ('3-AGAINST', '2-WITH'), ('3-AGAINST', '1-AGAINST'), ('3-WITH', '5-WITH'), ('4-WITH','2-AGAINST'),
                        ('2-AGAINST','1-AGAINST'), ('2-AGAINST','3-WITH'), ('5-WITH','4-WITH'), ('5-WITH','6-AGAINST')
])

实现思路与完整代码

核心逻辑

  1. 先提取图中所有强连通分量(SCC),作为聚类的基础单元,避免冗余计算
  2. 以带specialAttribute=True的节点为锚点,扩展合并相邻的SCC,确保合并后的子图仍为强连通
  3. 验证合并后的聚类:所有连接外部的边界节点必须是特殊节点
  4. 去重处理,避免生成重复聚类

完整实现代码

def identify_clusters(digraph):
    # 1. 提取所有强连通分量,按大小降序排序(优先处理大分量,提升效率)
    sccs = list(nx.strongly_connected_components(digraph))
    sccs.sort(key=len, reverse=True)
    
    # 2. 筛选所有特殊节点
    special_nodes = [n for n, attr in digraph.nodes(data=True) if attr.get('specialAttribute')]
    
    clusters = []
    visited_scc = set()  # 标记已处理的SCC,避免重复合并

    for scc in sccs:
        scc_frozen = frozenset(scc)
        if scc_frozen in visited_scc:
            continue
        
        # 跳过不含特殊节点的SCC(无法作为有效聚类的边界)
        if not any(n in special_nodes for n in scc):
            continue
        
        # 从当前SCC出发,扩展强连通区域
        current_cluster = set(scc)
        queue = list(scc)

        while queue:
            node = queue.pop()
            # 遍历节点的所有邻居和前驱,寻找可合并的SCC
            for neighbor in list(digraph.neighbors(node)) + list(digraph.predecessors(node)):
                # 找到邻居所属的SCC
                neighbor_scc = next((sc for sc in sccs if neighbor in sc), None)
                if not neighbor_scc:
                    continue
                ns_frozen = frozenset(neighbor_scc)
                if ns_frozen in visited_scc:
                    continue
                
                # 验证合并后的子图是否强连通
                temp_cluster = current_cluster.union(neighbor_scc)
                if nx.is_strongly_connected(digraph.subgraph(temp_cluster)):
                    current_cluster.update(neighbor_scc)
                    queue.extend(neighbor_scc)
                    visited_scc.add(ns_frozen)
        
        # 验证聚类的边界节点是否均为特殊节点
        is_valid = True
        for node in current_cluster:
            # 检查节点的外部邻居:若存在外部邻居,则该节点是边界节点,必须为特殊节点
            for neighbor in digraph.neighbors(node):
                if neighbor not in current_cluster and node not in special_nodes:
                    is_valid = False
                    break
            if not is_valid:
                break
        
        if is_valid and len(current_cluster) > 1:
            clusters.append(', '.join(sorted(current_cluster)))
    
    # 去重并返回结果
    return list(set(clusters))

# 测试示例
if __name__ == "__main__":
    clusters = identify_clusters(digraph)
    for idx, cluster in enumerate(clusters, 1):
        print(f"聚类{idx}: {cluster}")

方案适配性说明

  • 大规模图兼容:基于强连通分量的处理逻辑时间复杂度为O(V+E),适配4万节点的场景
  • 边界验证严格:确保所有连接聚类外部的节点都是特殊节点,符合需求
  • 灵活性:允许特殊节点跨多个聚类,满足示例中的重叠情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:13:15