[英]How to ensure minimum euclidean distance in a list of tuples
我有一個非常大的坐標列表,以元組列表的形式出現。
data = [(1,1),(1,11),(1,21),(11,1),(21,1),(11,11),(11,21),(21,11),(21,21),(1,2),(2,1)]
元組列表實際上是由帶有 append 命令的 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
附加點:雖然元組列表來自一些迭代的 function,但元組的順序是不確定的。 在 for 循環結束之前,元組的實際數量是未知的。 在這種情況下,我寧願避免多處理/多線程以加快速度。 如有必要,我可以提出一些時間安排,但我認為沒有必要。 我現在的解決方案是時間 O(n(n-1)/2) 和 O(n) 的空間復雜度,我認為任何改進都會更好。
您可以使用Quadtree組織您的 2D 數據/元組。
四叉樹是八叉樹的二維模擬,最常用於通過遞歸地將二維空間細分為四個象限或區域來划分二維空間。
你可以使用 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 ---
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.