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

NetworkX中如何将有向图双向边转换为无向边

NetworkX 有向图转仅保留双向边的无向图实现

转换规则说明:

  • 输出无向图h和输入有向图g的节点集合完全一致
  • 无向边(u, v)存在于h中,当且仅当g中同时存在u→v和v→u两条有向边

示例输入的有向图结构如下:
有向图示例
对应定义代码:

import networkx as nx
g = nx.DiGraph([("A", "B"), ("B", "A"), ("A", "C"), ("C", "A"), ("B", "C"), ("C", "B"), ("A", "D"), ("C", "D"), ("B", "E"), ("C", "E")])

期望输出的无向图结构如下:
无向图示例
对应定义代码:

h = nx.Graph([("A", "B"), ("A", "C"), ("B", "C")])
h.add_nodes_from(["D", "E"])

下面提供两种可直接使用的实现方案:

方案1:直接构造独立新图(易读性最高,适合初学者)

逻辑直观:先复制所有节点保证节点集合完全一致,再筛选双向存在的边加入无向图,最终得到的h是完全独立于g的新图,修改g不会影响h。

def f(g: nx.DiGraph) -> nx.Graph:
    h = nx.Graph()
    # 复制所有节点(包含节点自带属性)
    h.add_nodes_from(g.nodes(data=True))
    # 遍历所有有向边,筛选双向边
    for u, v in g.edges():
        # 加u<v判断是为了避免对同一对节点重复判断,提升效率
        # 如果节点是不支持大小比较的自定义类型,可以删掉这个判断,不影响最终结果
        if u < v and g.has_edge(v, u):
            h.add_edge(u, v, **g.edges[u, v])
    return h

测试验证:

h = f(g)
print(sorted(h.nodes())) # 输出 ['A', 'B', 'C', 'D', 'E']
print(sorted(h.edges())) # 输出 [('A', 'B'), ('A', 'C'), ('B', 'C')]

运行结果和预期完全一致。

方案2:用过滤器构造动态视图(内存占用更低)

即你提到的图视图+过滤器实现方式,这种方案不会复制原图数据,生成的h是和g动态关联的视图,修改g的边/节点时h会自动同步,适合处理大图、不需要独立副本的场景。

from networkx import graphviews

def f(g: nx.DiGraph) -> nx.Graph:
    # 先转成无向基础视图
    undirected_base = g.to_undirected(as_view=True)
    # 定义边过滤规则:仅保留双向都存在的边
    def is_bidirectional(u, v):
        return g.has_edge(u, v) and g.has_edge(v, u)
    # 返回过滤后的视图(默认保留所有节点,仅过滤边)
    return graphviews.subgraph_view(undirected_base, filter_edge=is_bidirectional)

如果需要把视图转成独立的静态图,只需要在外层套一层nx.Graph()即可:

h = nx.Graph(f(g))

内容的提问来源于stack exchange,提问作者W.P. McNeill

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.15 16:16:03