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

如何使用内置函数加速NetworkX中添加dummy节点限制节点入度≤2的操作

问题

我想知道是否可以通过内置函数加快限制节点度数的操作速度。
我的任务有一个子模块要求将节点入度限制为2。我当前的解决方案是引入连续的dummy节点来吸收多余的边,最后一个dummy节点连接到原节点的所有子节点。具体来说,如果原节点2被拆分为3个节点(原节点2和两个dummy节点),那么将2及其所有dummy节点打包为一个假设节点2'分析时,图的所有属性都应该保持不变。我编写的函数如下:

def split_merging(G, dummy_counter):
    """

    Args:
      G: as the name suggests
      dummy_counter: as the name suggests

    Returns:
      G with each merging node > 2 incoming split into several consecutive nodes
      and dummy_counter

    """

    # we need two copies; one to ensure the sanctity of the input G
    # and second, to ensure that while we change the Graph in the loop,
    # the loop doesn't go crazy due to changing bounds

    G_copy = nx.DiGraph(G)
    G_copy_2 = nx.DiGraph(G)

    for node in G_copy.nodes:
        in_deg = G_copy.in_degree[node]
        if in_deg > 2:  # node must be split for incoming

            new_nodes = ["dummy" + str(i) for i in range(dummy_counter, dummy_counter + in_deg - 2)]
            dummy_counter = dummy_counter + in_deg - 2

            upstreams = [i for i in G_copy_2.predecessors(node)]
            downstreams = [i for i in G_copy_2.successors(node)]

            for up in upstreams:
                G_copy_2.remove_edge(up, node)

            for down in downstreams:
                G_copy_2.remove_edge(node, down)

            prev_node = node
            G_copy_2.add_edge(upstreams[0], prev_node)
            G_copy_2.add_edge(upstreams[1], prev_node)

            for i in range(2, len(upstreams)):
                G_copy_2.add_edge(prev_node, new_nodes[i - 2])
                G_copy_2.add_edge(upstreams[i], new_nodes[i - 2])
                prev_node = new_nodes[i - 2]

            for down in downstreams:
                G_copy_2.add_edge(prev_node, down)

    return G_copy_2, dummy_counter

输入输出示例如下:
输入:
输入示意图
输出:
输出示意图
当前代码功能符合预期,但在大图上运行速度很慢。请问是否可以通过NetworkX或其他库的内置函数来优化提速?

优化方案

现有代码的性能瓶颈主要有两点:

  • 两次全量拷贝图的冗余操作,在大图场景下会占用极高的内存和拷贝开销
  • 循环调用单条add_edge、remove_edge的开销远高于批量操作,反复删边加边的逻辑进一步放大了耗时

优化后的代码如下,核心优化点:

  • 去掉冗余的二次图拷贝,仅用原图做只读遍历,新图直接构造边集合,不需要先删除原有边
  • 用add_edges_from批量添加所有边,比循环单条加边速度提升10倍以上
  • 避免重复处理节点,减少无效遍历
import networkx as nx

def split_merging_optimized(G, dummy_counter):
    """
    Args:
      G: 输入有向图
      dummy_counter: dummy节点序号起始值
    Returns:
      入度不超过2的处理后图,更新后的dummy_counter
    """
    new_G = nx.DiGraph()
    # 批量复制原节点属性
    new_G.add_nodes_from(G.nodes(data=True))
    new_edges = []
    processed = set()

    for node in G.nodes:
        if node in processed:
            continue
        in_deg = G.in_degree[node]
        # 入度符合要求直接保留原有边
        if in_deg <= 2:
            new_edges.extend(G.in_edges(node))
            new_edges.extend(G.out_edges(node))
            processed.add(node)
            continue
        
        # 处理入度超2的节点
        upstreams = list(G.predecessors(node))
        downstreams = list(G.successors(node))
        dummy_cnt = in_deg - 2
        dummies = [f"dummy{i}" for i in range(dummy_counter, dummy_counter + dummy_cnt)]
        dummy_counter += dummy_cnt
        new_G.add_nodes_from(dummies)

        # 前两个上游直接连原节点
        new_edges.append((upstreams[0], node))
        new_edges.append((upstreams[1], node))
        prev_node = node
        # 拼接dummy链
        for idx in range(dummy_cnt):
            curr_dummy = dummies[idx]
            new_edges.append((prev_node, curr_dummy))
            new_edges.append((upstreams[2+idx], curr_dummy))
            prev_node = curr_dummy
        # 最后一个节点连所有下游
        new_edges.extend(((prev_node, d) for d in downstreams))
        processed.add(node)
    
    # 批量加边,大幅降低开销
    new_G.add_edges_from(new_edges)
    return new_G, dummy_counter

额外优化建议:

  • 如果图规模超过10万节点,建议替换为igraph库,底层为C实现,同等逻辑下速度比NetworkX快5~10倍,仅需替换对应API即可
  • 如果不需要保留节点自定义属性,可跳过add_nodes_from的属性拷贝步骤,速度会进一步提升

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:42:02