簡體   English   中英

計算(x,y,z)點列表中最近鄰的(歐幾里得)距離的最有效方法是什么?

[英]What is the Most Efficient Way to Compute the (euclidean) Distance of the Nearest Neighbor in a List of (x,y,z) points?

為數組中的每個點計算最近鄰居的(歐幾里得)距離的最有效方法是什么?

我有一個 100k (X,Y,Z) 點的列表,我想計算最近鄰距離的列表。 距離的索引將對應於點的索引。

我調查了 PYOD 和 sklearn 鄰居,但這些似乎需要“教學”。 我認為我的問題比這更簡單。 對於每個點:找到最近的鄰居,計算距離。

示例數據:

points = [
     (0             0   1322.1695
      0.006711111   0   1322.1696
      0.026844444   0   1322.1697
      0.0604        0   1322.1649
      0.107377778   0   1322.1651
      0.167777778   0   1322.1634
      0.2416        0   1322.1629
      0.328844444   0   1322.1631
      0.429511111   0   1322.1627...)]

計算 k = 1 最近鄰距離

結果格式:

results = [nearest neighbor distance]

示例結果:

results = [
0.005939372
0.005939372
0.017815632
0.030118587
0.041569616
0.053475883
0.065324964
0.077200014
0.089077602)
]

更新:

我已經實施了兩種建議的方法。

  1. 使用 scipy.spatial.cdist 計算全距離矩陣
  2. 使用半徑 R 中最近的 X 個鄰居來查找每個點的鄰居距離子集並返回最小的。

結果是方法 2 比方法 1 更快,但需要付出更多努力才能實現(有道理)。

似乎方法 1 的限制因素是運行完整計算所需的 memory,尤其是當我的數據集接近 10^5 (x, y, z) 點時。 對於我的 23k 點數據集,捕獲最小距離大約需要 100 秒。

對於方法 2,速度縮放為 n_radius^2。 也就是說,“鄰居半徑平方”,這實際上意味着算法隨着包含的鄰居數量線性縮放。 使用大約 5 的半徑(給定應用程序綽綽有余),對於 23k 點的集合,需要 5 秒才能提供與 point_list 本身順序相同的分鍾列表。 “精確解”與方法二的差分矩陣基本為零。

感謝大家的幫助!

這個怎么樣?

from scipy.spatial import distance

A = (0.003467119 ,0.01422762 ,0.0101960126)
B = (0.007279433  ,0.01651597  ,0.0045558849)
C = (0.005392258  ,0.02149997  ,0.0177409387)
D = (0.017898802  ,0.02790659  ,0.0006487222)
E = (0.013564214  ,0.01835688  ,0.0008102952)
F = (0.013375397  ,0.02210725 ,0.0286032185)

points = [A, B, C, D, E, F]
results = []
for point in points:
    distances = [{'point':point, 'neighbor':p, 'd':distance.euclidean(point, p)} for p in points if p != point]
    results.append(min(distances, key=lambda k:k['d']))

結果將是一個對象列表,如下所示:

results = [
    {'point':(x1, y1, z1), 'neighbor':(x2, y2, z2), 'd':"distance from point to neighbor"},
...]

其中point是參考點, neighbor是點的最近鄰居。

您可以使用的最快選項可能是scipy.spatial.distance.cdist ,它會找到其輸入中所有點之間的成對距離。 雖然找到所有這些距離可能不是找到最近鄰居的最快算法,但 cdist 在cdist中實現,因此它可能比您在 Python 中嘗試的任何方法運行得更快。

import scipy as sp
import scipy.spatial
from scipy.spatial.distance import cdist

points = sp.array(...)
distances = sp.spatial.distance.cdist(points)

# An element is not its own nearest neighbor
sp.fill_diagonal(distances, sp.inf)

# Find the index of each element's nearest neighbor
mins = distances.argmin(0)

# Extract the nearest neighbors from the data by row indexing
nearest_neighbors = points[mins, :]

#  Put the arrays in the specified shape
results = np.stack((points, nearest_neighbors), 1)

理論上你可以讓這個運行更快(主要是通過將所有步驟組合到一個算法中),但除非你在 C 中編寫,否則你將無法與 SciPy/NumPy 競爭。

cdist在 Θ(n 2 ) 時間內運行(如果每個點的大小是固定的),並且算法的所有其他部分在 O(n) 時間內運行,因此即使您確實嘗試優化 Python 中的代碼,您也不會'不要注意到少量數據的變化,而cdist對於更多數據的改進會黯然失色。)

類似於 Caleb 的答案,但如果您獲得的距離大於之前的某個最小距離(抱歉 - 沒有代碼),您可以停止迭代循環。

我曾經為視頻游戲編程。 計算兩點之間的實際距離需要太多的 CPU。 我們所做的是將“屏幕”划分為更大的笛卡爾正方形,如果 Delta-X 或 Delta-Y “太遠”,則避免實際距離計算——這只是減法,所以也許類似的東西來限定實際歐幾里得的位置需要計算距離度量(根據需要擴展到 n 維)?

編輯 - 擴展“太遠”的候選對選擇評論。 為簡潔起見,我將假設一個二維景觀。 取興趣點 (X0,Y0) 並圍繞該點“繪制”一個 nxn 正方形,以 (X0,Y0) 為原點。

Go 通過初始點列表並形成該正方形內的候選點列表。 這樣做時,如果 DeltaX [ABS(Xi-X0)] 在正方形之外,則無需計算 DeltaY。

如果沒有候選點,則將正方形變大並迭代。

如果只有一個候選點並且它在正方形所包含的圓的半徑內,那就是你的最小值。

如果有“太多”的候選者,讓方塊變小,但你只需要從這個迭代中重新檢查候選者列表,而不是所有的點。

如果沒有“太多”候選者,則計算該列表的距離。 這樣做時,首先計算第一個候選者的 DeltaX^2 + DeltaY^2。 如果對於后續的候選人,到目前為止,DetlaX^2 大於最小值,則無需計算 DeltaY^2。

如果該計算的最小值在正方形內接圓的半徑內,則該最小值是最小值。

如果沒有,您需要將 go 返回到先前的候選列表,其中包括圓內具有該最小值的半徑的點。 例如,如果您在一個 2x2 正方形中以恰好位於頂點 X=1、Y=1 上的一個候選對象結束,則距離/半徑將為 SQRT(2)。 所以 go 回到先前的候選列表,其平方大於或等於 2xSQRT(2)。

如果有必要,生成一個僅包含 +/- SQRT(2) 平方的點的新候選列表。 如上所述計算這些候選點的距離 - 忽略任何超過迄今為止計算的最小值的距離。

在您只有一個候選人之前,無需計算 Delta^2 之和的平方根。

如何確定初始正方形的大小,或者它是否應該是一個矩形,以及如何增加或減小正方形/矩形的大小,可能會受到數據分布的應用知識的影響。

如果您使用的語言支持,我會考慮其中一些遞歸算法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM