Skip to main content
 首页 » 编程设计

python之欧氏距离(python3,sklearn): efficiently compute closest pairs and their corresponding distances

2024年10月01日11Terrylee

我得到一个由浮点值组成的二维 numpy 数组 X,需要计算所有行对之间的欧氏距离,然后计算距离最小的前 k 行索引并返回它们(其中 k > 0 ).我正在用一个小阵列进行测试,这是我目前所拥有的……

import numpy as np 
from sklearn.metrics.pairwise import euclidean_distances 
 
X_testing = np.asarray([[1,2,3.5],[4,1,2],[0,0,2],[3.4,1,5.6]]) 
test = euclidean_distances(X_testing, X_testing) 
print(test)   

结果打印输出是:

[[ 0.          3.5         2.6925824   3.34215499] 
 [ 3.5         0.          4.12310563  3.64965752] 
 [ 2.6925824   4.12310563  0.          5.05173238] 
 [ 3.34215499  3.64965752  5.05173238  0.        ]] 

接下来,我需要高效地计算出所有行对之间的前k个最小距离,并以列表的形式依次返回对应的k个(row1, row2, distance_value)元组。

所以在上面的测试用例中,如果 k = 2,那么我需要返回以下内容:

[(0, 2, 2.6925824), (0, 3, 3.34215499)]

是否有内置方法(scipy、sklearn、numpy 等)或任何其他方法来帮助高效计算?虽然上面的测试用例很小,但实际上二维数组非常大,所以内存和时间是一个问题。谢谢

请您参考如下方法:

使用 scipy.spatial 而不是 sklearn (我还没有安装)我可以获得相同的距离矩阵:

In [623]: from scipy import spatial 
In [624]: pdist=spatial.distance.pdist(X_testing) 
In [625]: pdist 
Out[625]:  
array([ 3.5       ,  2.6925824 ,  3.34215499,  4.12310563,  3.64965752, 
        5.05173238]) 
In [626]: D=spatial.distance.squareform(pdist) 
In [627]: D 
Out[627]:  
array([[ 0.        ,  3.5       ,  2.6925824 ,  3.34215499], 
       [ 3.5       ,  0.        ,  4.12310563,  3.64965752], 
       [ 2.6925824 ,  4.12310563,  0.        ,  5.05173238], 
       [ 3.34215499,  3.64965752,  5.05173238,  0.        ]]) 

pdist 是压缩形式,其在正方形中的索引可以用

In [629]: np.triu_indices(4,1) 
Out[629]:  
(array([0, 0, 0, 1, 1, 2], dtype=int32), 
 array([1, 2, 3, 2, 3, 3], dtype=int32)) 

2个最小的距离是第一个2个值

In [630]: idx=np.argsort(pdist) 
In [631]: idx 
Out[631]: array([1, 2, 0, 4, 3, 5], dtype=int32) 

所以我们想要 [1,2] 来自 pdisttriu 的相应元素:

In [633]: pdist[idx[:2]] 
Out[633]: array([ 2.6925824 ,  3.34215499]) 
In [634]: np.transpose(np.triu_indices(4,1))[idx[:2],:] 
Out[634]:  
array([[0, 2], 
       [0, 3]], dtype=int32) 

并将这些值收集为元组列表:

In [636]: I,J = np.triu_indices(4,1) 
In [637]: kbig = idx[:2] 
In [638]: [(i,j,d) for i,j,d in zip(I[kbig], J[kbig], pdist[kbig])] 
Out[638]: [(0, 2, 2.6925824035672519), (0, 3, 3.3421549934136805)] 

Numpy array of distances to list of (row,col,distance)