【问题标题】:How to ensure minimum euclidean distance in a list of tuples如何确保元组列表中的最小欧几里得距离
【发布时间】:2021-03-08 11:00:57
【问题描述】:

我有一个非常大的坐标列表,以元组列表的形式。

data = [(1,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21),(1,2),(2,1)]

元组列表实际上是由一个带有附加命令的 for 循环形成的,如下所示:

data = []
    for i in source: # where i a tuple of form (x,y)
        data.append(i)

有没有办法确保所有元组之间的欧几里得距离高于某个阈值?在这个例子中,(1,1),(1,2),(2,1) 之间的距离非常小。在这种情况下,我只想保留 3 个元组中的一个。产生这些新的元组列表之一:

data = [(1,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21)]
data = [(2,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21)]
data = [(1,2),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21)]

我有一个遍历列表的蛮力算法,但应该有更优雅或更快捷的方法来做到这一点?或者有没有其他方法可以加快这个操作?我期待大约 70k 到 500k 元组的列表。

我的方法:

from scipy.spatial.distance import euclidean
data = [(1,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21),(1,2),(2,1)]
new_data = []
while len(data) >0:
    
    check = data.pop()
    flag = True
    for i in data:
         if euclidean(check,i) < 5:
              flag = False
              break
         else:
              pass
    if flag == True:
        new_data.append(check)
    else:
        flag = True
    
         

补充点: 虽然元组列表来自一些迭代函数,但元组的顺序是不确定的。 在 for 循环结束之前,元组的实际数量是未知的。 在这种情况下,我宁愿避免多处理/多线程以加快速度。 如有必要,我可以提出一些时间安排,但我认为没有必要。 我现在的解决方案是时间 O(n(n-1)/2) 和 O(n) 的空间复杂度,我认为任何改进都会更好。

【问题讨论】:

    标签: python


    【解决方案1】:

    您可以使用Quadtree 组织您的二维数据/元组。

    四叉树是八叉树的二维模拟,最常用于通过递归地将二维空间细分为四个象限或区域来划分二维空间。

    【讨论】:

    • 嗨,Alex,我不太了解 Quadtrees 将如何提供帮助。据我所知,这意味着当我得到点时,它会构建一个具有一定宽度/高度的点节点......并且对于每个点,我检查它是否存在于任何点节点区域并创建一个新节点,如果它不存在吗?非常感谢您打算如何应用四叉树的代码示例。
    • 如果你用四叉树组织你的点,找到最近的邻居会很快。这对你有帮助吗? stackoverflow.com/questions/32412107/quadtree-find-neighbor
    • 啊,这解释得很好。感谢你的回答。稍后将接受为有效。如果有更新的解决方案也会很有趣。
    • 谢谢。你的问题很有趣,有可能得到富有成果的答案,我希望更多的人用他们的想法来回答。
    【解决方案2】:

    你可以使用 numpy 试试这个:

    import numpy as np
    
    data = [(1,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21),(1,2),(2,1)]
    start_time = time.time()
    #transform to numpy array
    a = np.array(data)
    subs = a[:,None] - a
    #calculate ecludien distance between all element
    dist=np.sqrt(np.einsum('ijk,ijk->ij',subs,subs))
    #replace 0 to 5 because distance distance between identic element will be 0
    dist=np.where(dist == 0, 5, dist)
    #select element where distance sup to 5
    dist_bool=[dist[:,0] < 5]
    #select element where distance sup to 5 are false 
    a=a[dist_bool[0] == False]
    print("--- %s seconds ---" % (time.time() - start_time))#got --- 0.00020575523376464844 seconds ---
    

    当我们与您的解决方案进行比较时:

    start_time = time.time()
    new_data = []
    while len(data) >0:
        check = data.pop()
        flag = True
        for i in data:
             if euclidean(check,i) < 5:
                  flag = False
                  break
             else:
                  pass
        if flag == True:
            new_data.append(check)
        else:
            flag = True
    print("--- %s seconds ---" % (time.time() - start_time))# got ---0.001013040542602539 seconds ---
    

    【讨论】:

    • 这个答案对你有帮助吗?
    • 您好,这是一个有趣的解决方案。感谢您的意见。
    • 如果您不感兴趣,可以进一步优化它
    猜你喜欢
    • 2021-10-01
    • 1970-01-01
    • 2013-03-02
    • 2015-07-15
    • 2014-02-04
    • 1970-01-01
    • 2018-08-05
    相关资源
    最近更新 更多