在计算欧几里得距离时,为什么逐列计算要比对整个DataFrame进行计算更快?

时间:2019-09-04 12:42:51

标签: python pandas performance dataframe

我有一个熊猫系列,其中包含点 p x y 坐标,以及一个包含多个点 q的DataFrame 1 q n (还有 x y )。然后,我计算 p 与每个 qs 之间的成对欧几里得距离。为了找到最有效的方法,我尝试了几种计算方法,其中两种方法引起了我的注意:

import pandas as pd

cs = pd.DataFrame([[10, 15], [56, 45], [33, 24]], columns=['x', 'y'])
pt = pd.Series({'x': 14, 'y': 32})

def d1(cls, pt):
    return ((pt['x'] - cls['x']) ** 2 + (pt['y'] - cls['y']) ** 2) ** 0.5

def d2(cls, pt):
    return ((pt - cls) ** 2).sum(axis=1) ** 0.5

第一个d1分别减去 x y 列并对其求平方,然后将它们相加,而d2减去这两个列同时进行减法,然后使用.sum()进行添加。

我期望d2会更快,但是在两个函数上都使用timeit时(运行7次,每个循环1000个),我发现d1的速度是{{1 }(690毫秒vs 1.9秒)。

这可能是什么原因?

1 个答案:

答案 0 :(得分:1)

d2性能较差的原因是组织数据帧操作(索引检查对齐等)的额外开销。尽管我无法解释所有细节,但您会了解基本概念从d1d2的配置文件图表中获取。

d1d2之间的差异将随着尺寸的增加而变小:在我的计算机上,我得到的d2 / d1执行时间比率是2.6、2.1和1.8分别用于2、3和4维。因此,我想对于足够多的维度d2可能比d1更快(未经测试)。

计算欧几里得距离的最快方法是使用SciPy中的cdist

from scipy.spatial import distance

def d3(cls, pt):
    return pd.Series(distance.cdist(cls, [pt]).ravel())

它至少比d1快5倍,并且实际上与尺寸数无关。 以下是我针对2、3和4维的timeitd1d2的{​​{1}}输出:

d3

从原始2D情况的性能图可以看出,2D 1000 loops, best of 3: 1.37 ms per loop 100 loops, best of 3: 3.61 ms per loop 1000 loops, best of 3: 246 µs per loop 3D 100 loops, best of 3: 2.05 ms per loop 100 loops, best of 3: 4.28 ms per loop 1000 loops, best of 3: 234 µs per loop 4D 100 loops, best of 3: 2.69 ms per loop 100 loops, best of 3: 5.06 ms per loop 1000 loops, best of 3: 237 µs per loop d1之间的差异也随着数据帧大小的增加而变小:

enter image description here