小编典典

欧氏距离的高效精确计算

python

继一些在线调查(12numpy的SciPy的scikit数学),我已经找到了计算的几种方法
在Python欧氏距离

# 1
numpy.linalg.norm(a-b)

# 2
distance.euclidean(vector1, vector2)

# 3
sklearn.metrics.pairwise.euclidean_distances

# 4
sqrt((xa-xb)^2 + (ya-yb)^2 + (za-zb)^2)

# 5
dist = [(a - b)**2 for a, b in zip(vector1, vector2)]
dist = math.sqrt(sum(dist))

# 6
math.hypot(x, y)

我想知道是否有人可以就 效率*精度 方面认为上述哪一项( 或我未找到的其他任何 理由)提供最佳见解。如果有人知道任何的
资源(S) ,其中讨论的主题,这也将是巨大的。
*** __

背景下 ,我在有趣的是,在计算对数元组之间的欧氏距离,例如之间的距离(52, 106, 35, 12)(33, 153, 75, 10)


阅读 213

收藏
2020-12-20

共1个答案

小编典典

结论第一:

timeit用于效率测试的测试结果中,我们可以得出 关于效率的 结论:

Method5 (zip, math.sqrt) > Method1 (numpy.linalg.norm)> Method2 (scipy.spatial.distance)>Method3 (sklearn.metrics.pairwise.euclidean_distances )

虽然我没有真正测试过您,Method4因为它不适合一般情况,通常等效于Method5

对于其余部分,令人惊讶的Method5是,它是最快的。虽然Method1它的用途numpy,如我们所期望的,这是用C大量优化,是第二快的。

因为scipy.spatial.distance,如果直接转到函数定义,您将看到它实际上正在使用numpy.linalg.norm,除了它将在real之前对两个输入向量执行验证numpy.linalg.norm。这就是为什么它慢一点的原因numpy.linalg.norm

最后对于sklearn,根据文档:

与其他计算距离的方式相比,此公式具有两个优点。首先,在处理稀疏数据时它的计算效率很高。其次,如果一个参数变化而另一个参数保持不变,则可以预先计算点(x,x)和/或点(y,y)。但是,这不是进行此计算的最精确方法,并且此函数返回的距离矩阵可能未按要求完全对称

由于在您的问题中您想使用一组固定的数据,因此未体现此实现的优势。而且由于性能和精度之间的权衡,它在所有方法中也给出了最差的精度。

关于精度Method5 = Metho1= Method2>Method3

效率测试脚本:

import numpy as np
from scipy.spatial import distance
from sklearn.metrics.pairwise import euclidean_distances
import math

# 1
def eudis1(v1, v2):
    return np.linalg.norm(v1-v2)

# 2
def eudis2(v1, v2):
    return distance.euclidean(v1, v2)

# 3
def eudis3(v1, v2):
    return euclidean_distances(v1, v2)

# 5
def eudis5(v1, v2):
    dist = [(a - b)**2 for a, b in zip(v1, v2)]
    dist = math.sqrt(sum(dist))
    return dist

dis1 = (52, 106, 35, 12)
dis2 = (33, 153, 75, 10)
v1, v2 = np.array(dis1), np.array(dis2)

import timeit

def wrapper(func, *args, **kwargs):
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

wrappered1 = wrapper(eudis1, v1, v2)
wrappered2 = wrapper(eudis2, v1, v2)
wrappered3 = wrapper(eudis3, v1, v2)
wrappered5 = wrapper(eudis5, v1, v2)
t1 = timeit.repeat(wrappered1, repeat=3, number=100000)
t2 = timeit.repeat(wrappered2, repeat=3, number=100000)
t3 = timeit.repeat(wrappered3, repeat=3, number=100000)
t5 = timeit.repeat(wrappered5, repeat=3, number=100000)

print('\n')
print('t1: ', sum(t1)/len(t1))
print('t2: ', sum(t2)/len(t2))
print('t3: ', sum(t3)/len(t3))
print('t5: ', sum(t5)/len(t5))

效率测试输出:

t1:  0.654838958307
t2:  1.53977598714
t3:  6.7898791732
t5:  0.422228400305

精密测试脚本和结果:

In [8]: eudis1(v1,v2)
Out[8]: 64.60650122085238

In [9]: eudis2(v1,v2)
Out[9]: 64.60650122085238

In [10]: eudis3(v1,v2)
Out[10]: array([[ 64.60650122]])

In [11]: eudis5(v1,v2)
Out[11]: 64.60650122085238
2020-12-20