欧几里德距离(python3,sklearn):有效地计算最近的对及其相应的距离

时间:2017-02-04 22:28:41

标签: python numpy scipy scikit-learn euclidean-distance

我给出了由浮动值组成的2-D 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.33415499)]

是否有内置方式(scipy,sklearn,numpy等)或其他任何有效计算方法?虽然上述测试用例很小,但实际上2-D阵列非常大,因此存储器和时间是一个问题。感谢

2 个答案:

答案 0 :(得分:2)

使用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]的{​​{1}}以及pdist的相应元素:

triu

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

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)

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

答案 1 :(得分:0)

这是示例,但包含列表推导,因此您可以看到切片。显然不是速度恶魔,而是更多的理解。

>>> import numpy as np
>>> a = np.random.randint(0,10, size=(5,5))
>>> a
array([[8, 3, 3, 8, 9],
       [0, 8, 6, 6, 5],
       [6, 7, 6, 5, 0],
       [4, 2, 4, 0, 3],
       [4, 1, 3, 2, 2]])
>>> idx = np.argsort(a, axis=1)
>>> idx
array([[1, 2, 0, 3, 4],
       [0, 4, 2, 3, 1],
       [4, 3, 0, 2, 1],
       [3, 1, 4, 0, 2],
       [1, 3, 4, 2, 0]])
>>> v = np.vstack([ a[i][idx[i]] for i in range(len(idx))])
>>> v
array([[3, 3, 8, 8, 9],
       [0, 5, 6, 6, 8],
       [0, 5, 6, 6, 7],
       [0, 2, 3, 4, 4],
       [1, 2, 2, 3, 4]])
>>> 
>>> v3 = np.vstack([ a[i][idx[i]][:3] for i in range(len(idx))])
>>> v3
array([[3, 3, 8],
       [0, 5, 6],
       [0, 5, 6],
       [0, 2, 3],
       [1, 2, 2]])
>>> 

如果你愿意的话,你可以把切片弄得一团糟,然后把它装满。