我有一个 pandas 系列,其中包含一个点 p 的 x 和 y 坐标,以及一个包含多个点 q 的 DataFrame 1 到 qn(还有 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
比 d2
快近三倍(690 毫秒对 1.9 秒)。
这可能是什么原因?
最佳答案
d2
性能较差的原因是组织数据帧操作的额外开销(索引检查对齐等)虽然我无法解释你会得到的每一个细节d1 的剖面图的基本概念和 d2 .
d1
和 d2
之间的差异会随着维度的增加而变小:在我的机器上我得到一个 d2
/d1
2、3 和 4 维的执行时间比率分别为 2.6、2.1 和 1.8。所以我猜对于足够多的维度,d2
可能比 d1
更快(未测试)。
计算欧氏距离的最快方法是使用 cdist
来自 SciPy
:
from scipy.spatial import distance
def d3(cls, pt):
return pd.Series(distance.cdist(cls, [pt]).ravel())
它至少比 d1
快 5 倍,而且实际上不依赖于维数。
以下是我对 d1
、d2
和 d3
的 2、3 和 4 维度的 timeit
输出:
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
从原始 2D 案例的性能图中可以看出,d1
和 d2
之间的差异也随着数据帧大小的增加而变小:
关于python - 为什么在计算欧几里德距离时,按列计算比 Pandas 中整个 DataFrame 的计算更快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57788654/