【问题标题】:Most Efficient Method of Searching Neighbour Data for Nth Neighbour搜索第 N 个邻居的邻居数据的最有效方法
【发布时间】:2013-11-11 14:38:05
【问题描述】:

问题

我的程序生成了几组数据,使我能够在 tkinter 画布上渲染顶点网络及其连接。我需要能够找到网络中每个顶点的第 N 个邻居。

我的代码已经确定了每个顶点与其直接邻居的连接,这意味着使用列表推导可以轻松找到第一组邻居,使用列表推导将所选顶点作为搜索数据的值。我实际上想以最有效的方法对每个邻居重复此搜索。正在搜索的数据(我已经计算过)在下面的代码中指定为p_2,格式为:(原点坐标,邻居坐标),Coordinates_xyz 是一个列表网络的唯一顶点。下面的代码演示了我当前如何仅识别第一个邻居。

再说一次,我已经有了所有的邻居数据,我只需要最好的方法来搜索这些数据以找到到每个顶点的连接。

清晰度:

我正在尝试做的示例:
我的程序生成的一种数据表示重复正方形模式的顶点网络。每个顶点(远离边缘)有 4 个邻居,然后每个邻居有 4 个邻居(尽管这些邻居中的一个邻居是前一个顶点,所以被打折了)等等。 如果我选择坐标为 (x20, y20, z20) 的顶点 20 并在 p_2 中搜索邻居,它可能会返回(例如):
(来源),(邻居)
(x20, y20, z20), (x21, y21, z21)
(x23, y23, z23), (x20, y20, z20)
(x26, y26, z23), (x20, y20, z20)
(x20, y20, z20), (x30, y30, z30)
然后我可以清楚地看到顶点 21、23、26 和 30 是网络中与顶点 20 的相邻点。但是,我需要分别重复 21、23、26 和 30 的搜索过程以找到第二个最近的邻居。对于 N 个最近的邻居,我必须找到一种方法来制定一种有效(尽可能)的方法,对每个邻居重复此搜索并从顶点 20 向外进行,同时跟踪邻居的顺序。同样,我知道这会对大 N 造成负担,但它通常不会在 N>4 时运行。 下面的代码解决了我的 N = 1 问题。

matching_1_NN_list=[]
matching_1_NN_list[:]=[]    
for vertex in xrange(len(Coordinates_xyz)):
    #Target vertex Coordinates_xyz[vertex] 
    matching_1_NN = [x for x in p_2 if Coordinates_xyz[vertex] in x]
    matching_1_NN_Component_0=column(matching_1_NN, 0)
    matching_1_NN_Component_1=column(matching_1_NN, 1)
    for x in matching_1_NN_Component_0:
        if x == Coordinates_xyz_final[vertex]:
            pass
        else:
            x=x, vertex, 1 #coordinates, vertex number, order (1 = first neighbour)
            matching_1_NN_list.append(x)


    for x in matching_1_NN_Component_1:
        if x == Coordinates_xyz_final[vertex]:
            pass
        else:
            x=x, vertex, 1
            matching_1_NN_list.append(x)
    matching_1_NN_list=set(list(matching_1_NN_list)) #Removes Duplicates

【问题讨论】:

  • “最多第二个最近的邻居”是什么意思?它是“最多 2 个最近的邻居”或“第二个最近的邻居”。您使用的“第 N 个邻居”的概念也存在同样的问题 - 它没有意义。
  • 无法理解。您是在谈论最近的空间邻居吗?如果是这样,您在代码中的哪个位置计算距离?
  • 如果您的意思是最近的空间邻居并且这不是一个学习练习,请使用docs.scipy.org/doc/scipy/reference/generated/…
  • 抱歉,当我说“最多第二个最近的邻居”时,我的意思是我希望找到并包括所有第一和第二个邻居。再次,对于任何混淆,我深表歉意,并将更新问题以澄清问题。我只是希望避免任何只返回第二个 NN 的响应。
  • @MarkyD43 如果您能够发布尽可能完整且尽可能少的代码,这将很有帮助。完整含义:如果我们可以直接运行您提供的代码并自己查看问题,那将是最好的。事实上,我们只能猜测程序的其余部分在做什么以及问题可能出在哪里。最小含义:尝试在没有任何不相关部分的情况下呈现您的代码 - 在向我们展示之前尝试隔离问题。删掉一些函数调用并替换为虚拟值等。请参阅:sscce.org 如果你能做到这一点,你会得到更好的答案!

标签: python performance list list-comprehension


【解决方案1】:

似乎在优化这方面很大一部分是改进您搜索邻居的方式。在您当前的方法中,您循环遍历整个对列表并为每次进行大量成员资格检查,您需要找到一个顶点的邻居。最好只执行一次此步骤,然后在字典中查找结果。例如,如果您有以下顶点:

 7 |  E
 6 |
 5 |
 4 |  D
 3 |
 2 |     B  C
 1 |  A
 0 +----------
   0  1  2  3

使用以下最近邻居列表:

p_2 = [('A', 'B'),
       ('B', 'C'),
       ('C', 'B'),
       ('D', 'B'),
       ('E', 'D')]

你可以这样做,例如:

from collections import defaultdict

p_2_dict = defaultdict(set)
for a, b in p_2:
    p_2_dict[a].add(b)
    p_2_dict[b].add(a)

def find_neigbours(start_vertex, levels):
    found = []
    from_vertices = [start_vertex]
    for i in range(1, levels+1):
        new_from_vertices = []
        for vertex in from_vertices:
            for neighbour in p_2_dict[vertex]:
                new_from_vertices.append(neighbour)
                found.append( (neighbour, i) )
        from_vertices = new_from_vertices
    return found

但是,这会发现很多重复项。就像您在示例代码中所做的那样,您可以使用集合来仅存储唯一值。此外,如果您遇到起始顶点,您可以跳过它。

def find_neigbours(start_vertex, levels):
    found = set()
    from_vertices = [start_vertex]
    for i in range(1, levels+1):
        new_from_vertices = set()
        for vertex in from_vertices:
            for neighbour in p_2_dict[vertex]:
                if neighbour == start_vertex:
                    continue
                new_from_vertices.add(neighbour)
                found.add( (neighbour, i) )
        from_vertices = new_from_vertices
    return found

不过,如果与之关联的“邻居的顺序”与已存储的不同,则它会存储重复的顶点。你想用这些做什么?只存储第一次遇到特定顶点的顺序?

输出:

In [49]: find_neigbours('A', 1)
Out[49]: set([('B', 1)])

In [50]: find_neigbours('A', 2)
Out[50]: set([('B', 1), ('D', 2), ('C', 2)])

# 'B' encountered with different order:
In [51]: find_neigbours('A', 3)
Out[51]: set([('B', 1), ('D', 2), ('B', 3), ('E', 3), ('C', 2)])

【讨论】:

  • 这已经过时了,我只是要把它改编成我的代码,但是非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-01-19
  • 2019-06-05
  • 2020-01-29
  • 2023-03-20
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 2020-03-05
相关资源
最近更新 更多