Suu*_*hgi 8 python dijkstra shortest-path networkx osmnx
我有一个很大的osmnx(networkx)图,并且nx.all_pairs_dijkstra_path_length需要很长时间才能计算。
有哪些可能性可以加快计算速度?
import osmnx as ox\nimport networkx as nx\nRun Code Online (Sandbox Code Playgroud)\n让我们占领这个区域
\ncoords, dist = (51.5178, 9.9601), 9000\nG = ox.graph.graph_from_point( coords, dist=dist, network_type=\'drive\', simplify=True)\nG = ox.add_edge_speeds(G)\nG = ox.add_edge_travel_times(G)\nRun Code Online (Sandbox Code Playgroud)\n以nx.all_pairs_dijkstra_path_length作为基线。
为此,让我们创建简写bench_nx:
bench_nx = lambda G, weight=\'travel_time\': sum((l:=[ d for t in nx.all_pairs_dijkstra_path_length(G, weight=weight) for d in t[1].values() ])) / len(l)\nRun Code Online (Sandbox Code Playgroud)\nbench_nx(G)\n582.2692172953298\nRun Code Online (Sandbox Code Playgroud)\n%timeit -n 3 -r 2 bench_nx(G)\n53.7 s \xc2\xb1 101 ms per loop (mean \xc2\xb1 std. dev. of 2 runs, 3 loops each)\nRun Code Online (Sandbox Code Playgroud)\ndef mp_all_pairs_dijkstra_path_length(G, cutoff=None, weight=\'weight\'):\n    """\n    Multi-core version of\n    nx.all_pairs_dijkstra_path_length\n    """\n\n    import multiprocessing as mp\n    from functools import partial\n\n    f = partial(nx.single_source_dijkstra_path_length,\n                G, cutoff=cutoff, weight=weight)\n\n    with mp.Pool(mp.cpu_count()) as p:\n        \n        lengths = p.map(f, G)\n        for n, l in zip(G, lengths):\n            yield n, l\nRun Code Online (Sandbox Code Playgroud)\nbench_mp = lambda G, weight=\'travel_time\': sum((l:=[ d for t in mp_all_pairs_dijkstra_path_length(G, weight=weight) for d in t[1].values() ])) / len(l)\nRun Code Online (Sandbox Code Playgroud)\nbench_mp(G)\n582.2692172953298\nRun Code Online (Sandbox Code Playgroud)\n%timeit -n 3 -r 2 bench_mp(G)\n20.2 s \xc2\xb1 754 ms per loop (mean \xc2\xb1 std. dev. of 2 runs, 3 loops each)\nRun Code Online (Sandbox Code Playgroud)\n图表越大,这里的优势似乎就越大。
\n使用图形工具我们可以加快速度。
\n图形工具使用整数索引顶点和边。因此我在这里创建两个字典
\nnx_node->gt_idxu,v,k(边缘)->gt_idx能够映射从nx到gt。
import graph_tool.all as gt\nfrom collections import defaultdict\n\nG_gt = gt.Graph(directed=G.is_directed())\n\n# "Dict" [idx] = weight\nG_gt_weights = G_gt.new_edge_property("double")\n\n# mapping of nx vertices to gt indices\nvertices = {}\nfor node in G.nodes:\n    \n    v = G_gt.add_vertex()\n    vertices[node] = v\n\n# mapping of nx edges to gt edge indices\nedges = defaultdict(lambda: defaultdict(dict))\n\nfor src, dst, k, data in G.edges(data=True, keys=True):\n    \n    # Look up the vertex idxs from our vertices mapping and add edge.\n    e = G_gt.add_edge(vertices[src], vertices[dst])\n    edges[src][dst][k] = e\n    \n    # Save weights in property map\n    G_gt_weights[e] = data[\'travel_time\']\nRun Code Online (Sandbox Code Playgroud)\n注意:我添加了截止点,1e50因为gt将不可到达的目的地设置为 distance 1.79e308。
bench_gt = lambda G, weights: sum((l:=[ d for l in gt.shortest_distance(G, weights=weights) for d in l if 0 < d <= 1e50 ])) / len(l)\nRun Code Online (Sandbox Code Playgroud)\nbench_gt(G_gt, G_gt_weights)\n582.4092142257183\nRun Code Online (Sandbox Code Playgroud)\n%timeit -n 3 -r 2 bench_gt(G_gt, G_gt_weights)\n4.76 s \xc2\xb1 27.4 ms per loop (mean \xc2\xb1 std. dev. of 2 runs, 3 loops each)\nRun Code Online (Sandbox Code Playgroud)\n这至少提高了 11 倍。
\n事实证明distance_histogram(),如果在编译时启用,则能够进行二次采样并并行运行!
import osmnx as ox\nimport networkx as nx\nRun Code Online (Sandbox Code Playgroud)\ncoords, dist = (51.5178, 9.9601), 9000\nG = ox.graph.graph_from_point( coords, dist=dist, network_type=\'drive\', simplify=True)\nG = ox.add_edge_speeds(G)\nG = ox.add_edge_travel_times(G)\nRun Code Online (Sandbox Code Playgroud)\n注:由于第一个 bin 内的差异,存在小偏差。如果有人知道原因,我很高兴知道!\n编辑这似乎是graph-tools 中的一个错误。
bench_nx = lambda G, weight=\'travel_time\': sum((l:=[ d for t in nx.all_pairs_dijkstra_path_length(G, weight=weight) for d in t[1].values() ])) / len(l)\nRun Code Online (Sandbox Code Playgroud)\n这又是 50 倍,总加速为 241 倍!
\n|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           787 次  |  
        
|   最近记录:  |