【问题标题】:Euclidean distances (python3, sklearn): efficiently compute closest pairs and their corresponding distances欧几里得距离(python3,sklearn):有效地计算最近的对及其对应的距离
【发布时间】:2017-06-22 03:07:19
【问题描述】:

我得到一个由浮点值组成的二维 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个最小距离,并以列表的形式依次返回(row1, row2, distance_value)对应的k个元组。

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    >>> 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]])
    >>> 
    

    如果你愿意,你可以随意切片并将其放入完整的 np。

    【讨论】:

      【解决方案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 个最小的距离是 1st 2 的值

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

      所以我们想要来自pdist[1,2]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)
      

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

      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)

      【讨论】:

        【解决方案3】:

        为什么不在 sklearn 中使用NearestNeighbors

        参考here

        nbrs = NearestNeighbors(**n_neighbors=3**,algorithm='kd_tree').fit(a) 
        
        distances, indices = nbrs.kneighbors(a)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-29
          • 2018-02-14
          • 2019-03-08
          • 2013-04-07
          • 2021-01-31
          • 2015-09-23
          相关资源
          最近更新 更多