【问题标题】:The shortest path length between neighbors of connected vertices (not any two random vertices!)连接顶点的邻居之间的最短路径长度(不是任何两个随机顶点!)
【发布时间】:2019-09-05 12:29:04
【问题描述】:

我之前问过一个类似的问题,但我认为还不清楚。我有一个10000 顶点和5000000 边的无向和未加权图,我将它们作为边列表读入python。

在我的工作中,我试图从每条边构建一个函数,该函数取决于每条边上相邻顶点之间的距离。假设我们有两个连接的顶点 v1,v2 表示一条边,对于 v1 有 n1 个连接的邻居,也有 n2 个连接到 v2 的邻居。为了构建我的函数,我需要获取 n1 和 n2 邻居之间的距离。对于图中的所有边,函数如下所示:

e_1*d_1 +e_1*d_2 +...+e_1*d_n+...e_m*d_1+...e_m*d_n

其中 n 是每条边上两个顶点的邻居数,d_n 是顶点之间的距离,m 是图中的边数,e_m 是该图中的最后一条边。

通常,如果我们想获得最短路径长度,我们会考虑像 Dijkstra 算法或 Bfs 这样的图遍历,尤其是我的图未加权。我使用了许多已经编写在包中的函数,例如 networkx 和 igraph,但是这些函数效率不高,并且在我的图表上花费了大量时间。例如函数 shortest_paths_dijkstra() 需要大约 6.9 小时才能获得距离,因为我需要多次调用它。此外,函数all_pairs_shortest_path _length 需要大约 13 分钟(通过将称为截止的路径长度固定为 3)和另外 16 分钟来调用图中每对邻居的距离!

正如问题中所写,我们需要获取 v1、v2 的邻居之间的距离,因此最大距离为 3,因为 v1、v2 是连接的。我觉得有一个更聪明的解决方案来降低时间复杂度,方法是使用路径的可能距离(在我的情况下)是0, 1, 2, 3,因为所以我不需要遍历整个图之间的每条路径源头和目标!只是我正在寻找一种聪明的方法来获取邻居之间的距离(不是任意两个随机顶点)!

我写了这段代码,但它需要很长时间,大约 54 分钟,所以效率也不高!

neighbor1 = {}
neighbor2 = {}
distance = {}
for i in list(edges.values()):
  list_of_distances = []
  neighbor1 = tuple(graph.vs[graph.neighbors(i[0], mode="all")]["name"])
  neighbor2 = tuple(graph.vs[graph.neighbors(i[1], mode="all")]["name"])
  for n2 in neighbor2:
    for n1 in neighbor1:
       if n1 == n2:
            list_of_distances.append(0)
       elif (n1 != n2) and not graph.are_connected(n1,n2):
            if ( graph.are_connected(i[0],n2) ) or ( graph.are_connected(n1,i[1])  ): 
               list_of_distances.append(2)
            elif ( not graph.are_connected(i[0],n2)  ) or ( not graph.are_connected(n1,i[1]) ):
               list_of_distances.append(3)
       else:
            list_of_distances.append(1)
  distance[tuple(i)] = list_of_distances

我想知道是否有另一种不需要大量内存和时间来获得这些距离的方法,或者是否可以修改一个像 Bfs 或 Dijkstra 这样的图形遍历方法,所以没有必要每次迭代都搜索整个图,并在本地做一些事情(如果可以说的话)。感谢您的帮助

【问题讨论】:

  • 定义你要的函数:参数,返回值。
  • 如果Vx 和Vy (直接)连接它们之间的距离是多少?您如何获得零距离?
  • @wwii Vx==Vy.
  • @wwii 表示图中边的任意两个顶点之间的距离固定为 1,因为它们是连接的。事实上,我不计算这些顶点之间的距离,而是我需要得到它们的邻居之间的距离,所以如果两个顶点都有一个共同的邻居,那么距离就是 0
  • 你的功能有点不清楚,e_1之类的值是多少?也许添加你用来计算它的代码会有所帮助

标签: python algorithm networkx igraph shortest-path


【解决方案1】:

您有极其繁重的计算任务,因此您的脚本运行数小时是正常的。您可以尝试将其与 CUDA 或类似的东西并行化,或者您可以尝试构建一个大型缓存 (GB)。但是如果你不能或不想,我建议你不要使用 networkx/igraph 函数,因为它们对你来说非常慢。您可以在没有 1000000 次 DFS 运行的情况下解决您的问题。这是使用 Python 集的可能解决方案之一(我认为它会比你的更快,也许不是很快)。

import networkx as nx

# Create a graph like yours
G = nx.fast_gnp_random_graph(1000, 0.05)

# Create neighbours dict
G_adj = dict(G.adjacency())
nbrs_dict = {node: {n for n in G_adj[node]} for node in G_adj}

# Result dict
distances = {}

# For every edge:
for e in G.edges:

    # Start value
    dist_value = 0

    # Get N1 and N2 neighbours
    n1_nbrs = nbrs_dict[e[0]]
    n2_nbrs = nbrs_dict[e[1]]

    # Triangles - nodes that connected to both N1 and N2
    # Every triangle value = 0
    tri = n1_nbrs & n2_nbrs
    for t in tri:

        # Get neighbours to find nodes with distance length = 2
        t_nbrs = nbrs_dict[t]

        t_in_n1 = n1_nbrs & t_nbrs
        t_in_n2 = n2_nbrs & t_nbrs

        t_not_in_n1 = n1_nbrs - t_nbrs
        t_not_in_n2 = n2_nbrs - t_nbrs

        dist_value += len(t_in_n1) + len(t_in_n2)
        dist_value += (2 * len(t_not_in_n1)) + (2 * len(t_not_in_n2))

    # Exclude all triangle nodes because we processed them all
    n1nt_nbrs = n1_nbrs - tri
    n2nt_nbrs = n2_nbrs - tri

    # Select squares - nodes with length = 1
    direct = set([])
    for n1 in n1nt_nbrs:
        nbrs = nbrs_dict[n1]
        d = nbrs & n2nt_nbrs
        for node in d:
            direct.add((n1, node))
    dist_value += len(direct)

    # Exclude squares so we have only nodes with length = 3
    n1final = n1nt_nbrs - set(e[0] for e in direct)
    n2final = n2nt_nbrs - set(e[1] for e in direct)
    dist_value += 3 * len(n1final) * len(n2final)

    # Distance for an edge
    distances[e] = dist_value

无论如何,您的问题具有O(n^3) 的复杂性,因此我强烈建议您尝试拆分图表。也许你有bridges 或者只有几个连接的组件。如果您将它们分开处理,您将大大提高您的速度。

【讨论】:

  • 感谢您的帮助。我还没有分析你的算法,但作为第一步,我检查了结果距离,这很奇怪!我在这个小图上应用了代码: 1 2 2 3 2 4 3 4 4 5 每条边上顶点的邻居之间的距离字典应该是这样的 {('1', '2'): [1, 1, 1], ('2', '3'): [1, 1, 1, 2, 1, 0], ('2', '4'): [1, 1, 1, 2, 0, 1, 3, 2, 1], ('3', '4'): [0, 1, 1, 1, 2, 1], ('4', '5'): [1, 1, 1] } 而你的距离是 {('1', '2'): 9, ('2', '3'): 10, ('2', '4'): 13, ('3', '4' ): 10, ('4', '5'): 9}?我不明白发生了什么!
  • 这个算法不会单独计算每个可能的长度,所以我希望它会更快。它构造具有每个长度的节点对组,乘以它的长度并总结它。据我了解,你不需要这些数组,你需要它们的总和,所以这种算法是适用的。
  • 坏消息:如果你需要数组,我的算法没用,你应该使用你的(也许我对邻居字典的修改,我认为它会工作得更快一些)。在这种情况下,我强烈建议您尝试拆分图表,因为您的算法对于您的问题几乎是最佳的。如果你需要更快的速度,你应该使用 C++。
  • 1.我不是很正确,它不是 O(N^3),它只是立方。您有 N 个节点和 E 条边。对于每条边 (E),您检查所有邻居对,即avg(nbrs)^2。 avg(nbrs) 可以表示为 (E/N),所以我们有 O(E^3/N^2) 和 E >> N。
  • 2.我建议你使用 Gephi 软件。您可以使用强制布局仔细查看您的图表,您可以使用许多分析函数等。您还可以使用 networkx(bridges、connectivity 和其他类型的算法)分析您的图表。
猜你喜欢
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 2016-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多