NetworkX: shortest path and length.
2-line summary
shortest path with weight.
- 오늘 이야기할 것은 사실 좀 사소한 것일 수도 있습니다.
- 보통
networkx를 이용해서 분석을 할 때,weight를 고려하고 싶은 경우에는weight=True의 형태로 argument를 넘겨줍니다. 보통 이렇게 하면 알아서, weight를 고려해서 처리해주니까요. - 하지만,
nx.shortest_path를 계산할 때는 이렇게 argument를 넘겨주면 weight를 고려해주지 않습니다.
USE nx.shortest_path(G, weight=True)
nx.shortest_path(G, weight=True)와 같이, arugmentweight에 대해서True를 넘겨줍니다.
import networkx as nx
import numpy as np
import itertools
"""
shortest_path_length(weight=True) doesn't mean weight sum.
"""
np.random.seed(0)
G = nx.complete_graph(3)
# UPDATE edge attr with 'weight'
edge_weight_dict = {(0, 1): 1.5, (0, 2): 3.5, (1, 2): 5.5}
nx.set_edge_attributes(G, edge_weight_dict, name='weight')
for u, v in itertools.combinations(G, 2):
# weight에 True를 넘겨줬습니다.
s_p = nx.shortest_path(G, u, v, weight=True)
print(f"== shortest path from node {u} to node {v} :: {s_p}")
s_p_l = nx.shortest_path_length(G, u, v, weight=True)
print(f"== shortest path length from node {u} to node {v} :: {s_p_l}")
- 해당 graph
G는 node 1에서 node 2로 갈 때, weight를 고려한다면, shortest path가(0, 1, 2)로 가는게 맞습니다만, 결과가 그렇게 나오지 않죠. 그냥 weight를 고려하지 않은 경우와 동일한 결과가 나옵니다.
== shortest path from node 0 to node 1 :: [0, 1]
== shortest path length from node 0 to node 1 :: 1
== shortest path from node 0 to node 2 :: [0, 2]
== shortest path length from node 0 to node 2 :: 1
== shortest path from node 1 to node 2 :: [1, 2]
== shortest path length from node 1 to node 2 :: 1
USE nx.shortest_path(G, weight='weight')
- 사실, 이 부분은
networkx에 좀 아쉽기도 한데요, 다음과 같이, 정확한 edge attribute 내의 key를 넘겨줘야 합니다.
nx.shortest_path(G, weight='weight')
- 자, 이제 이렇게 해서 실행을 하면 잘 되는 것을 알 수 있죠.
import networkx as nx
import numpy as np
import itertools
"""
shortest_path_length(weight=True) doesn't mean weight sum.
shortest_path_length(weight='weight') mean weight sum.
"""
np.random.seed(0)
G = nx.complete_graph(3)
# UPDATE edge attr with 'weight'
edge_weight_dict = {(0, 1): 1.5, (0, 2): 3.5, (1, 2): 5.5}
nx.set_edge_attributes(G, edge_weight_dict, name='weight')
for u, v in itertools.combinations(G, 2):
s_p = nx.shortest_path(G, u, v, weight='weight')
print(f"== shortest path from node {u} to node {v} :: {s_p}")
s_p_l = nx.shortest_path_length(G, u, v, weight='weight')
print(f"== shortest path length from node {u} to node {v} :: {s_p_l}")
- 결과를 보시면 weight를 정확하게 고려하여 shortest_path를 계산하는 것을 알 수 있습니다.
== shortest path from node 0 to node 1 :: [0, 1]
== shortest path length from node 0 to node 1 :: 1.5
== shortest path from node 0 to node 2 :: [0, 2]
== shortest path length from node 0 to node 2 :: 3.5
== shortest path from node 1 to node 2 :: [1, 0, 2]
== shortest path length from node 1 to node 2 :: 5.0
wrap-up
- 사실, 저는 이 부분이 조금 아쉽다고 느껴지기도 합니다. 다른 많은 함수들에서는 쉽게
weight=True를 사용하면서, 여기서만, 정확한attr_key를 넘기도록 된 건 좀 아쉬워요. - 오히려, True로 argument가 넘어왔을 때도 알아서 label을 인식해서 처리해주었으면 얼마나 좋았을까, 싶네요.
reference
GitHub에서 이 글의 마크다운 원본 보기 & 수정 제안src/content/posts/2020-02-28-nx_shortest_path