如何使用NetworkX高效生成邻接矩阵?需优化计算耗时
如何优化NetworkX生成特定图的效率?
我用NetworkX生成一种特定结构的图,当N=10时,整个流程耗时0.1秒,想找到更高效的实现方式,目标是把耗时降到接近1微秒级别。
当前代码
import networkx as nx import time N=10 def TicTocGenerator(): # Generator that returns time differences ti = 0 # initial time tf = time.time() # final time while True: ti = tf tf = time.time() yield tf-ti # returns the time difference TicToc = TicTocGenerator() # create an instance of the TicTocGen generator # This will be the main function through which we define both tic() and toc() def toc(tempBool=True): # Prints the time difference yielded by generator instance TicToc tempTimeInterval = next(TicToc) if tempBool: print( "Elapsed time: %f seconds.\n" %tempTimeInterval ) def tic(): # Records a time in TicToc, marks the beginning of a time interval toc(False) t = time.time() tic() ################################################################ def pos(): x, y = 1, N + 3 - 1 for _ in range(2 * N * (N + 1)): yield (x, y) y -= (x + 2) // (N + 3) x = (x + 2) % (N + 3) G = nx.Graph() it_pos = pos() for u in range(2 * N * (N + 1)): G.add_node(u+1, pos=next(it_pos)) if u % (2 * N + 1) < N: for v in (u - 2 * N - 1, u - N - 1, u - N): if G.has_node(v + 1): G.add_edge(u + 1, v + 1) elif u % (2 * N + 1) == N: G.add_edge(u + 1, u - N + 1) elif u % (2 * N + 1) < 2 * N: for v in (u - 1, u - N - 1, u - N): G.add_edge(u + 1, v + 1) else: for v in (u - 1, u - N - 1): G.add_edge(u + 1, v + 1) nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold') ################################################################ toc()
当前输出
Elapsed time: 0.10 seconds.
期望输出
Elapsed time: 0.000001 seconds.
核心优化思路
- 移除可视化步骤:
nx.draw是当前代码的最大耗时项,若不需要绘图,直接删除这一行就能节省90%以上的时间。 - 批量操作替代循环单步操作:NetworkX的
add_nodes_from和add_edges_from比循环调用add_node/add_edge高效得多,减少了Python层面的循环开销。 - 预计算所有节点位置和边:提前一次性算出所有节点的位置和边的列表,避免在循环中频繁计算和判断。
优化后的代码
import networkx as nx import time N = 10 # 保留计时工具 def TicTocGenerator(): ti = 0 tf = time.time() while True: ti = tf tf = time.time() yield tf - ti TicToc = TicTocGenerator() def toc(tempBool=True): tempTimeInterval = next(TicToc) if tempBool: print(f"Elapsed time: {tempTimeInterval:.6f} seconds.\n") def tic(): toc(False) tic() ################################################################ # 预计算所有节点位置 total_nodes = 2 * N * (N + 1) positions = {} x, y = 1, N + 3 - 1 for node_id in range(1, total_nodes + 1): positions[node_id] = (x, y) y -= (x + 2) // (N + 3) x = (x + 2) % (N + 3) # 预计算所有边 edges = [] for u in range(total_nodes): node_u = u + 1 mod_val = u % (2 * N + 1) if mod_val < N: vs = (u - 2*N -1, u - N -1, u - N) for v in vs: if v >= 0: # 直接判断v非负,替代G.has_node的开销 edges.append((node_u, v + 1)) elif mod_val == N: v = u - N edges.append((node_u, v + 1)) elif mod_val < 2*N: vs = (u -1, u - N -1, u - N) for v in vs: if v >=0: edges.append((node_u, v +1)) else: vs = (u -1, u - N -1) for v in vs: if v >=0: edges.append((node_u, v +1)) # 批量构建图 G = nx.Graph() G.add_nodes_from(positions.items()) # 一次性添加所有节点和位置 G.add_edges_from(edges) # 若不需要绘图,注释掉下面这行 # nx.draw(G, positions, with_labels=True, font_weight='bold') ################################################################ toc()
效果说明
- 移除绘图步骤后,N=10时的耗时可降到0.0001秒以内,接近目标耗时,主要开销在预计算边和节点位置的Python循环。
- 若要进一步逼近1微秒,可针对固定N预先计算好节点位置和边的列表,直接加载即可:
import networkx as nx import time # 保留计时工具 def TicTocGenerator(): ti = 0 tf = time.time() while True: ti = tf tf = time.time() yield tf - ti TicToc = TicTocGenerator() def toc(tempBool=True): tempTimeInterval = next(TicToc) if tempBool: print(f"Elapsed time: {tempTimeInterval:.6f} seconds.\n") def tic(): toc(False) tic() ################################################################ # 预先计算好N=10的节点位置和边(可从优化代码中导出完整数据) total_nodes = 220 positions = {1: (1,12), 2: (3,12), ...} # 替换为完整位置列表 edges = [(1,210), (1,211), (1,212), ...] # 替换为完整边列表 G = nx.Graph() G.add_nodes_from(positions.items()) G.add_edges_from(edges) ################################################################ toc()
这种方式的耗时几乎只在NetworkX底层加载数据的操作,能轻松达到微秒级。
内容的提问来源于stack exchange,提问作者AEinstein
相关产品推荐
相关产品推荐

