python - 高效精准的欧式距离计算

标签 python python-3.x euclidean-distance

经过一些在线研究( 12numpyscipyscikitmath ),我找到了几种在 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)

我想知道是否有人可以提供关于上述哪一个(或我尚未找到的任何其他)在效率方面被认为是最好的见解以及精度。如果有人知道任何讨论该主题的资源,那就太好了。

我感兴趣的上下文是计算数字元组对之间的欧几里得距离,例如(52, 106, 35, 12)之间的距离和(33, 153, 75, 10) .

最佳答案

首先结论:

从使用timeit进行效率测试的结果来看,我们可以得出以下结论:关于效率:

方法5(zip,math.sqrt) > 方法1(numpy.linalg.norm) > 方法2(scipy.spatial.distance) > 方法3(sklearn.metrics.pairwise.euclidean_distances)

虽然我没有真正测试您的Method4,因为它不适合一般情况,并且通常相当于Method5

对于其余的,令人惊讶的是,Method5 是最快的。而对于使用 numpyMethod1 来说,正如我们所期望的那样,它在 C 语言中进行了大量优化,是第二快的。

对于scipy.spatial.distance,如果直接进入函数定义,您会看到它实际上使用numpy.linalg.norm,只不过它会在实际的 numpy.linalg.norm 之前对两个输入向量执行验证。这就是为什么它比 numpy.linalg.norm 稍慢的原因。

最后是 sklearn,根据文档:

This formulation has two advantages over other ways of computing distances. First, it is computationally efficient when dealing with sparse data. Second, if one argument varies but the other remains unchanged, then dot(x, x) and/or dot(y, y) can be pre-computed. However, this is not the most precise way of doing this computation, and the distance matrix returned by this function may not be exactly symmetric as required

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

关于精度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

关于python - 高效精准的欧式距离计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37794849/

相关文章:

python - 使用 import keras 和 import tensorflow.keras 之间的区别?

Python BeautifulSoup 如何获取 HTML 表的索引

Python 3 编码错误谷歌翻译 API

python - 错误 - 在 python 中计算 PCA 的欧几里得距离

matlab - Octave pdist(成对距离)

matlab - 如何定义KNN的权重?

Python:如果脚本在 requests.get() 执行时停止会怎样?

python - 为什么 setuptools 不复制我的文件,而 distutils 却复制?

python - 我在使用 im.show() 时遇到错误

python - 如何使用子进程来回答 shell 提示?