【问题标题】:How to calculate distance for every row in a pandas dataframe from a single point efficiently?如何有效地计算熊猫数据框中每一行与单点的距离?
【发布时间】:2020-10-18 05:34:47
【问题描述】:

我有意见

point = np.array([0.07852388, 0.60007135, 0.92925712, 0.62700219, 0.16943809,
       0.34235233])

还有一个熊猫数据框

           a           b           c           d           e           f
0   0.025641    0.554686    0.988809    0.176905    0.050028    0.333333
1   0.027151    0.520914    0.985590    0.409572    0.163980    0.424242
2   0.028788    0.478810    0.970480    0.288557    0.095053    0.939394
3   0.018692    0.450573    0.985910    0.178048    0.118399    0.484848
4   0.023256    0.787253    0.865287    0.217591    0.205670    0.303030

我想计算 pandas 数据框中每一行到那个特定点的距离

我试过了

import numpy as np
d_all = list()
for index, row in df_scaled[cols_list].iterrows():
        d = np.linalg.norm(centroid-np.array(list(row[cols_list])))
        d_all += [d]
df_scaled['distance_cluster'] = d_all

我的解决方案确实很慢(考虑到我还想计算与其他点的距离。

有没有办法让我的计算更有效率?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    另一种选择是使用cdist,它会更快一点:

    from scipy.spatial.distance import cdist
    cdist(point[None,], df.values)
    

    输出:

    array([[0.47468985, 0.25707985, 0.70385676, 0.5035961 , 0.46115096]])
    

    与 100k 行的一些比较:

    %%timeit -n 10
    cdist([point], df.values)
    645 µs ± 36.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %%timeit -n 10
    np.linalg.norm(df.to_numpy() - point, axis=1)
    5.16 ms ± 227 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %%timeit -n 10
    df.sub(point, axis=1).pow(2).sum(axis=1).pow(.5)
    16.8 ms ± 444 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    【讨论】:

    • 这是一个不错的选择,但需要额外的包/导入,通常没有问题,但有些人可能会反对必须安装新库。此外,您的里程可能会因您的数据而异。
    【解决方案2】:

    您可以使用公式计算矢量化欧几里得距离(L2 范数)

    sqrt((a1 - b1)2 + (a2 - b2)2 + ...)

    df.sub(point, axis=1).pow(2).sum(axis=1).pow(.5)
    
    0    0.474690
    1    0.257080
    2    0.703857
    3    0.503596
    4    0.461151
    dtype: float64
    

    它提供与您当前代码相同的输出。


    或者,使用linalg.norm

    np.linalg.norm(df.to_numpy() - point, axis=1)
    # array([0.47468985, 0.25707985, 0.70385676, 0.5035961 , 0.46115096])
    

    【讨论】:

      【解决方案3】:

      让我们做scipy

      from scipy.spatial import distance
      ary = distance.cdist(df.values, np.array([point]), metric='euclidean')
      ary
      Out[57]: 
      array([[0.47468985],
             [0.25707985],
             [0.70385676],
             [0.5035961 ],
             [0.46115096]])
      

      【讨论】:

        【解决方案4】:

        有点晚了,但是你可以apply np.ligalg.norm 函数到数据帧。

        df['distance_cluster'] = df.apply(lambda x : np.linalg.norm(x-point),1)
        

        输出

        #print(df['distance_cluster'])
        
        0    0.474690
        1    0.257080
        2    0.703857
        3    0.503596
        4    0.461151
        dtype: float64
        

        但是,与numpy 解决方案相比,它会慢很多。

        【讨论】:

          猜你喜欢
          • 2020-06-06
          • 2020-04-29
          • 1970-01-01
          • 2022-12-17
          • 2019-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-07
          相关资源
          最近更新 更多