Python 连接顶点相邻点之间的最短路径长度(不是任意两个随机顶点!)

Python 连接顶点相邻点之间的最短路径长度(不是任意两个随机顶点!),python,algorithm,networkx,igraph,shortest-path,Python,Algorithm,Networkx,Igraph,Shortest Path,我以前问过一个类似的问题,但我想,这个问题并不清楚。我有一个无向且未加权的图,其中包含10000顶点和大约5000000边,我将它们作为边列表读给python 在我的工作中,我试图从每条边构建一个函数,该函数取决于每条边上相邻顶点之间的距离。假设我们有两个连接的顶点v1,v2代表一条边,对于v1,有n1个连接的邻居,也有n2个连接到v2的邻居。为了构建我的函数,我需要得到n1和n2邻居之间的距离。对于图形中的所有边,函数如下所示: e_1*d_1 +e_1*d_2 +...+e_1*d_n+..

我以前问过一个类似的问题,但我想,这个问题并不清楚。我有一个无向且未加权的图,其中包含
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\u paths\u dijkstra()
需要大约6.9小时才能获得距离,因为我需要多次调用它。另外,函数
all_pairs\u shortest_path\u 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,这样就不必每次迭代都搜索整个图,只需做一些局部的事情(如果可以说的话)。感谢您的帮助

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


无论如何,您的问题具有
O(n^3)
复杂性,因此我强烈建议您尝试拆分图形。可能您有或只是有几个连接的组件。如果你将它们分开处理,你将难以置信地提高你的速度。

定义你所追求的函数:参数,返回值。如果
Vx
Vy
是(直接)连接的,它们之间的距离是多少?如何获得零距离?@wwii
Vx==Vy
@wwii任意两个顶点之间的距离表示图形中的边,因为它们是连接的,所以固定为1。事实上,我没有计算这些顶点之间的距离,但是我需要得到它们相邻点之间的距离,如果两个顶点都有一个共同的相邻点,那么距离是0。你的函数有点不清楚,e_1的值是多少?也许添加用于计算它的代码会有所帮助谢谢您的帮助。我还没有分析你的算法,但作为第一步,我检查了结果距离,这很奇怪!我在这个小图上应用了这个代码:1 2 2 3 4 5每个边上顶点邻域之间距离的结果字典应该如下{('1','2'):[1,1,1],('2','3'):[1,1,1,1,2,1,0],('2','4'):[1,1,1,2,0,1,3,2,1],('3','4'):[0,1,1,1,1],('4','5'):[1,1,1]),而你的距离是{('1', '2'): 9, ('2', '3'): 10, ('2', '4'): 13, ('3', '4'): 10, ('4', '5'): 9}?我不明白发生了什么!这个算法没有单独计算每个可能的长度,所以我希望它会更快。它用每个长度构造节点对组,乘以其长度并汇总。据我所知,你不需要这些数组,你需要它们的和,所以这种算法是适用的。坏消息:如果你需要数组,我的算法是无用的,你应该使用你的(也许我对dict做了一些修改,我想它会运行得更快一些)在这种情况下,我强烈建议您尝试拆分您的图表,因为您的算法对您的问题几乎是最优的。如果您需要更多的速度,则应该使用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分析图形(
桥接
连接
和其他类型的算法)。
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