继一些在线调查(1,2,numpy的,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)。
(52, 106, 35, 12)
(33, 153, 75, 10)
从timeit用于效率测试的测试结果中,我们可以得出 关于效率的 结论:
timeit
Method5 (zip, math.sqrt) > Method1 (numpy.linalg.norm)> Method2 (scipy.spatial.distance)>Method3 (sklearn.metrics.pairwise.euclidean_distances )
Method5 (zip, math.sqrt)
Method1 (numpy.linalg.norm)
Method2 (scipy.spatial.distance)
Method3 (sklearn.metrics.pairwise.euclidean_distances )
虽然我没有真正测试过您,Method4因为它不适合一般情况,通常等效于Method5。
Method4
Method5
对于其余部分,令人惊讶的Method5是,它是最快的。虽然Method1它的用途numpy,如我们所期望的,这是用C大量优化,是第二快的。
Method1
numpy
因为scipy.spatial.distance,如果直接转到函数定义,您将看到它实际上正在使用numpy.linalg.norm,除了它将在real之前对两个输入向量执行验证numpy.linalg.norm。这就是为什么它慢一点的原因numpy.linalg.norm。
scipy.spatial.distance
numpy.linalg.norm
最后对于sklearn,根据文档:
sklearn
与其他计算距离的方式相比,此公式具有两个优点。首先,在处理稀疏数据时它的计算效率很高。其次,如果一个参数变化而另一个参数保持不变,则可以预先计算点(x,x)和/或点(y,y)。但是,这不是进行此计算的最精确方法,并且此函数返回的距离矩阵可能未按要求完全对称
由于在您的问题中您想使用一组固定的数据,因此未体现此实现的优势。而且由于性能和精度之间的权衡,它在所有方法中也给出了最差的精度。
关于精度 , Method5 = Metho1= Method2>Method3
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