【问题标题】:Distance calculation between rows in Pandas Dataframe using a distance matrix使用距离矩阵计算 Pandas Dataframe 中行之间的距离
【发布时间】:2013-12-16 16:29:15
【问题描述】:

我有以下 Pandas 数据框:

In [31]:
import pandas as pd
sample = pd.DataFrame({'Sym1': ['a','a','a','d'],'Sym2':['a','c','b','b'],'Sym3':['a','c','b','d'],'Sym4':['b','b','b','a']},index=['Item1','Item2','Item3','Item4'])
In [32]: print(sample)
Out [32]:
      Sym1 Sym2 Sym3 Sym4
Item1    a    a    a    b
Item2    a    c    c    b
Item3    a    b    b    b
Item4    d    b    d    a

我想根据这个距离矩阵找到优雅的方法来获取每个Item 之间的距离:

In [34]:
DistMatrix = pd.DataFrame({'a': [0,0,0.67,1.34],'b':[0,0,0,0.67],'c':[0.67,0,0,0],'d':[1.34,0.67,0,0]},index=['a','b','c','d'])
print(DistMatrix)
Out[34]:
      a     b     c     d
a  0.00  0.00  0.67  1.34
b  0.00  0.00  0.00  0.67
c  0.67  0.00  0.00  0.00
d  1.34  0.67  0.00  0.00 

例如,比较 Item1Item2 将比较 aaab -> accb -- 使用距离矩阵,这将是 0+0.67+0.67+0=1.34

理想输出:

       Item1   Item2  Item3  Item4
Item1      0    1.34     0    2.68
Item2     1.34    0      0    1.34
Item3      0      0      0    2.01
Item4     2.68  1.34   2.01    0

【问题讨论】:

    标签: python matrix pandas time-series euclidean-distance


    【解决方案1】:

    这是一个老问题,但是有一个 Scipy 函数可以做到这一点:

    from scipy.spatial.distance import pdist, squareform
    
    distances = pdist(sample.values, metric='euclidean')
    dist_matrix = squareform(distances)
    

    pdist 在 Numpy 矩阵上运行,DataFrame.values 是数据帧的底层 Numpy NDarray 表示。 metric 参数允许您选择几个内置距离度量之一,或者您可以传入任何二进制函数以使用自定义距离。它非常强大,而且根据我的经验,速度非常快。结果是一个“平面”数组,仅包含距离矩阵的上三角形(因为它是对称的),不包括对角线(因为它始终为 0)。 squareform 然后将这个扁平形式转换成一个完整的矩阵。

    docs 有更多信息,包括许多内置距离函数的数学概要。

    【讨论】:

      【解决方案2】:

      对于大数据,我找到了一种快速的方法。假设您的数据已经是 np.array 格式,命名为 a。

      from sklearn.metrics.pairwise import euclidean_distances
      dist = euclidean_distances(a, a)
      

      以下是比较两种方法所需时间的实验:

      a = np.random.rand(1000,1000)
      import time 
      time1 = time.time()
      distances = pdist(a, metric='euclidean')
      dist_matrix = squareform(distances)
      time2 = time.time()
      time2 - time1  #0.3639109134674072
      
      time1 = time.time()
      dist = euclidean_distances(a, a)
      time2 = time.time()
      time2-time1  #0.08735871315002441
      

      【讨论】:

        【解决方案3】:

        这需要做两倍的工作,但在技术上也适用于非对称距离矩阵(不管它是什么意思)

        pd.DataFrame ( { idx1: { idx2:sum( DistMatrix[ x ][ y ]
                                          for (x, y) in zip( row1, row2 ) ) 
                                 for (idx2, row2) in sample.iterrows( ) } 
                         for (idx1, row1 ) in sample.iterrows( ) } )
        

        您可以通过分段编写来使其更具可读性:

        # a helper function to compute distance of two items
        dist = lambda xs, ys: sum( DistMatrix[ x ][ y ] for ( x, y ) in zip( xs, ys ) )
        
        # a second helper function to compute distances from a given item
        xdist = lambda x: { idx: dist( x, y ) for (idx, y) in sample.iterrows( ) }
        
        # the pairwise distance matrix
        pd.DataFrame( { idx: xdist( x ) for ( idx, x ) in sample.iterrows( ) } )
        

        【讨论】:

          猜你喜欢
          • 2011-09-21
          • 2016-11-29
          • 2018-08-05
          • 1970-01-01
          • 1970-01-01
          • 2020-03-13
          • 2018-12-02
          • 1970-01-01
          相关资源
          最近更新 更多