如何用NumPy计算欧几里得距离?

790 投票
26 回答
1435226 浏览
提问于 2025-04-15 14:12

我在三维空间里有两个点:

a = (ax, ay, az)
b = (bx, by, bz)

我想计算这两个点之间的距离:

dist = sqrt((ax-bx)^2 + (ay-by)^2 + (az-bz)^2)

我该如何用NumPy来做到这一点呢?我有:

import numpy
a = numpy.array((ax, ay, az))
b = numpy.array((bx, by, bz))

26 个回答

183

对于那些想要一次计算多个距离的人,我用我的一个小项目 perfplot 做了一些比较。

首先的建议是,整理你的数据,使得数组的维度是 (3, n)(而且显然要是C语言连续存储的)。如果在连续的第一维度上进行加法运算,速度会更快。而且不管你是用 sqrt-sum 配合 axis=0,还是用 linalg.norm 配合 axis=0,效果差别不大,或者

a_min_b = a - b
numpy.sqrt(numpy.einsum('ij,ij->j', a_min_b, a_min_b))

这个方法是稍微快一点的变体。(其实这对于只有一行的数据也是成立的。)

而如果你在第二个轴上进行求和,也就是 axis=1,那么速度就会明显慢很多。

enter image description here


下面是重现这个图的代码:

import numpy
import perfplot
from scipy.spatial import distance


def linalg_norm(data):
    a, b = data[0]
    return numpy.linalg.norm(a - b, axis=1)


def linalg_norm_T(data):
    a, b = data[1]
    return numpy.linalg.norm(a - b, axis=0)


def sqrt_sum(data):
    a, b = data[0]
    return numpy.sqrt(numpy.sum((a - b) ** 2, axis=1))


def sqrt_sum_T(data):
    a, b = data[1]
    return numpy.sqrt(numpy.sum((a - b) ** 2, axis=0))


def scipy_distance(data):
    a, b = data[0]
    return list(map(distance.euclidean, a, b))


def sqrt_einsum(data):
    a, b = data[0]
    a_min_b = a - b
    return numpy.sqrt(numpy.einsum("ij,ij->i", a_min_b, a_min_b))


def sqrt_einsum_T(data):
    a, b = data[1]
    a_min_b = a - b
    return numpy.sqrt(numpy.einsum("ij,ij->j", a_min_b, a_min_b))


def setup(n):
    a = numpy.random.rand(n, 3)
    b = numpy.random.rand(n, 3)
    out0 = numpy.array([a, b])
    out1 = numpy.array([a.T, b.T])
    return out0, out1


b = perfplot.bench(
    setup=setup,
    n_range=[2 ** k for k in range(22)],
    kernels=[
        linalg_norm,
        linalg_norm_T,
        scipy_distance,
        sqrt_sum,
        sqrt_sum_T,
        sqrt_einsum,
        sqrt_einsum_T,
    ],
    xlabel="len(x), len(y)",
)
b.save("norm.png")
248

使用 scipy.spatial.distance.euclidean

from scipy.spatial import distance
a = (1, 2, 3)
b = (4, 5, 6)
dst = distance.euclidean(a, b)
1311

使用 numpy.linalg.norm

dist = numpy.linalg.norm(a-b)

之所以这样做是因为欧几里得距离就是l2范数,而在 numpy.linalg.norm 中,ord 参数的默认值就是2。想了解更多理论知识,可以看看数据挖掘导论

在这里输入图片描述

撰写回答