创建一个networkx加权图并找到权重最小的2个节点之间的路径

时间:2019-03-28 16:58:54

标签: python networkx graph-theory

我有一个涉及图论的问题。为了解决这个问题,我想使用networkx创建一个加权图。目前,我有一个字典,其中每个键是一个节点,每个值是相关的权重(介于10到20万之间)。

weights = {node: weight}

我相信我不需要通过网络标准化权重。 目前,我通过添加边来创建非加权图:

def create_graph(data):
    edges = create_edges(data)

    # Create the graph
    G = nx.Graph()

    # Add edges
    G.add_edges_from(edges)

    return G

根据我的阅读,我可以为边缘添加权重。但是,我希望将权重应用于特定节点而不是边缘。我该怎么办?

构想:我通过添加加权后的节点来创建图形,然后在节点之间添加边。

def create_graph(data, weights):
    nodes = create_nodes(data)
    edges = create_edges(data) # list of tuples

    # Create the graph
    G = nx.Graph()

    # Add edges
    for node in nodes:
        G.add_node(node, weight=weights[node])

    # Add edges
    G.add_edges_from(edges)

    return G

这种方法正确吗?

下一步是找到权重最小的2个节点之间的路径。我发现此功能:networkx.algorithms.shortest_paths.generic.shortest_path,我认为它做对了。但是,它在边缘使用权重而不是在节点上使用权重。有人可以解释一下此功能的作用,对节点的权重与对边缘的权重之间的区别是什么,以及如何实现所需的功能?谢谢:)

1 个答案:

答案 0 :(得分:1)

这通常看起来是正确的。

您可以使用bidirectional_dijkstra。如果您知道路径的源节点和目标节点,则速度会大大提高(请参阅底部的评论)。

要处理边缘与节点权重问题,有两个选项。首先请注意,您位于路径上节点的总和之后。如果我给每个边一个权重w(u,v) = w(u) + w(v),则沿此的权重之和为w(source) + w(target) + 2 sum(w(v)),其中节点v是沿途找到的所有节点。具有这些边缘权重的最小权重将具有带有节点权重的最小权重。

因此,您可以将每个边的权重分配为两个节点的总和。

for edge in G.edges():
    G.edges[edge]['weight'] = G.nodes[edge[0]]['weight'] + G.nodes[edge[1]]['weight']

但是另一种方法是注意输入bidirectional_dijkstra的权重可以是将边作为输入的函数。定义自己的函数以给出两个节点权重之和:

def f(edge):
    u,v = edge
    return G.nodes[u]['weight'] + G.nodes[v]['weight']

然后在您的通话中执行bidirectional_dijkstra(G, source, target, weight=f)

因此,我建议的选择是为每个边缘分配的权重等于节点权重之和,或者定义一个函数,该函数将仅针对算法遇到的边缘给出这些权重。在效率方面,我希望找出哪种方法比编写任何一种算法要花更多的时间。唯一的性能问题是分配所有权重将使用更多的内存。假设内存不是问题,请使用您认为最容易实现和维护的内存。


关于双向dijkstra的一些评论:假设您在空间中有两个点,它们之间的距离为R,而您想找到它们之间的最短距离。 dijkstra算法(默认为shortest_path)将探索源点距离D内的每个点。基本上,这就像在第一个点居中展开一个气球,直到到达另一个。它的体积为(4/3)pi R ^ 3。使用bidirectional_dijkstra,我们使每个气球居中膨胀,直到它们接触为止。它们各自的半径为R / 2。因此,体积为(4/3)pi(R / 2)^ 3 +(4/3)pi(R / 2)^ 3,是原始气球体积的四分之一,因此该算法探索了四分之一空间。由于网络可以具有很高的有效维度,因此节省的费用通常更大。