用NumPy计算欧几里得距离

779 阅读5分钟

在本指南中,我们将看看如何在Python中使用Numpy计算两点之间的欧氏距离。

什么是欧几里得距离?

欧氏距离是一个与欧氏空间中的系统有关的基本距离度量。

欧氏空间是你在数学课上熟悉的经典几何空间,通常被限定为3维。虽然,它也可以适用于任何非负的整数维。

欧几里得距离是欧几里得空间中两点之间最短的直线。

这个名字来自于欧几里德,他被广泛认为是*"几何学之父",因为这是当时人们通常会想到的唯一空间。随着时间的推移,人们在物理学和数学中观察到了不同类型的空间,如Affine空间*,而非欧几里得空间和几何学对于我们的认知是非常不直观的。

在3维欧几里得空间中,两点之间最短的线永远是它们之间的直线,尽管这在更高维度上并不成立。

鉴于这一事实,在处理许多维度时,欧氏距离并不总是最有用的指标,我们将专注于二维和三维欧氏空间来计算欧氏距离。

测量高维数据的距离通常是用其他距离指标,如曼哈顿距离

一般来说,欧氏距离在三维世界的发展中有着重要的用途,以及包含距离度量的机器学习算法,如K-Nearest Neighbors。通常情况下,欧氏距离将代表两个数据点的相似程度--假设已经根据其他数据进行了一些聚类。

数学公式

计算二维空间中两点之间的欧氏距离的数学公式:
$
d(p,q) = sqrt[2]{(q_1-p_1)^2 + (q_2-p_2)^2 }

该公式很容易适应三维空间,以及任何维度。该公式很容易适应三维空间,以及任何维度。

d(p,q) = \sqrt[2]{(q_1-p_1)^2 + (q_2-p_2)^2 + (q_3-p_3)^2 }
一般公式可以简化为:一般公式可以简化为:
d(p,q) = \sqrt[2]{(q_1-p_1) ^2 + ...+ (q_n-p_n)^2 }

眼尖的人可能会注意到欧氏距离和毕达哥拉斯定理的相似性:眼尖的人可能会注意到欧氏距离和毕达哥拉斯定理的相似性:

C^2 = A^2 + B^2

$ d(p,q)^2 = (q\_1-p\_1)^2 + (q\_2-p\_2)^2

事实上,这些之间存在着一种关系--欧氏距离是通过毕达哥拉斯定理计算的,给定两点的笛卡尔坐标。

正因为如此,欧氏距离有时也被称为毕达哥拉斯距离,不过,前者的名字更为人所知。

注意:两点是向量,但输出应该是一个标量(也就是距离)。

我们将使用NumPy来计算两点的这个距离,同样的方法也用于二维和三维空间。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')

ax.scatter(0, 0, 0)
ax.scatter(3, 3, 3)
plt.show()

two points in euclidean space

用NumPy在Python中计算欧几里得距离

首先,我们需要安装NumPy库。

$ pip install numpy

现在,让我们导入它并设置我们的两个点,直角坐标为(0,0,0)和(3,3,3)。

import numpy as np
# Initializing the points
point_1 = np.array((0, 0, 0))
point_2 = np.array((3, 3, 3))

现在,让我们利用NumPy的辅助方法,而不是手动进行计算,使之变得更加简单

np.sqrt()np.sum()

计算欧氏距离所需的操作和数学函数相当简单:加法减法以及平方根函数。多次加法也可以用来代替:
$
d(p,q) = \sqrt[2]{(q_1-p_1)^2 + (q_2-p_2)^2 + (q_3-p_3)^2 }

NumPy为我们提供了一个`np.sqrt()` 函数,代表平方根函数,以及一个`np.sum()` 函数,代表一个和。有了这些,在Python中计算欧几里得距离就简单而直观了。 ``` # Get the square of the difference of the 2 vectors square = np.square(point_1 - point_2) # Get the sum of the square sum_square = np.sum(square) ``` 这给了我们一个相当简单的结果。 ``` (0-3)^2 + (0-3)^2 + (0-3)^2 ``` 这等于*27*。剩下的就是得到这个数字的平方根。 ``` # The last step is to get the square root and print the Euclidean distance distance = np.sqrt(sum_square) print(distance) ``` 这就得出了。 ``` 5.196152422706632 ``` 本着真正的Pythonic精神,这可以缩短到只有一行。 ``` distance = np.sqrt(np.sum(np.square(point_1 - point_2))) ``` `math` 你甚至可以用Python的`pow()` 和`sum()` 模块的内置方法来代替,尽管它们需要你对输入进行一些修改,这很方便地用NumPy进行了抽象,因为`pow()` 函数只对标量(数组中的每个元素都是单独的)工作,并且接受一个参数--你要把数字提高到哪个幂。 不过,这种方法在直觉上*看起来*更像我们以前使用的公式。 ``` from math import * distance = np.sqrt(sum(pow(a-b, 2) for a, b in zip(point_1, point_2))) print(distance) ``` 这也导致了。 ``` 5.196152422706632 ``` ### *np.linalg.norm()* `np.linalg.norm()` 函数表示一个*数学规范*。从本质上讲,一个向量的*规范*就是它的*长度*。这个长度不一定是*欧氏距离*,也可以是其他距离。欧氏距离是**一个向量的L2规范**(有时被称为**欧氏规范**),默认情况下,`norm()` 函数使用L2--`ord` 参数被设置为2。 如果你将`ord` 参数设置为其他值*p*,你就会计算其他*p规范*。例如,*一个向量的L1准则是曼哈顿距离*! 考虑到这一点,我们可以使用`np.linalg.norm()` 函数来计算欧氏距离,而且比使用其他函数要简单得多。 ``` distance = np.linalg.norm(point_1-point_2) print(distance) ``` 这样,L2/Euclidean距离就会被打印出来。 ``` 5.196152422706632 ``` *L2归一化*和*L1归一化*在机器学习中被大量使用,用于归一化输入数据。 > 如果你想了解更多关于特征缩放的信息--请阅读我们的《[使用Scikit-Learn对数据进行特征缩放指南》](https://stackabuse.com/feature-scaling-data-with-scikit-learn-for-machine-learning-in-python/)! ### *np.dot()* 我们也可以用一个 ***点积***来计算欧几里得距离。在数学中,*点积*是两个等长的向量相乘的结果,其结果是一个单一的数字--标量值。由于返回类型的关系,它有时也被称为a ***"标量乘积"***.这个操作通常被称为两个向量的**内积**。 要计算2个向量之间的点积,可以使用以下公式:

\vec{p}

\cdot

\cdot \vec{q} = {(q_1-p_1) + (q_2-p_2) + (q_3-p_3) }

使用NumPy,我们可以使用`np.dot()` 函数,传入两个向量。 如果我们计算这两个点之间的差值的点积,再加上这个差值--我们会得到一个与这两个向量之间的欧几里得距离有关的数字。提取这个数字的平方根,就可以得到我们要找的距离。 ``` # Take the difference between the 2 points diff = point_1 - point_2 # Perform the dot product on the point with itself to get the sum of the squares sum_square = np.dot(diff, diff) # Get the square root of the result distance = np.sqrt(sum_square) print(distance) ``` 当然,你也可以把它缩短为一个单行代码。 ``` distance = np.sqrt(np.dot(point_1-point_2, point_1-point_2)) print(distance) ``` ``` 5.196152422706632 ``` ### 使用内置的*math.dist()* Python 在`math` 模块里有一个内置的方法,可以计算三维空间中两点之间的距离。然而,这只适用于Python 3.8或更高版本。 `math.dist()` dist()接收两个参数,即两个点,并返回这两个点之间的欧几里得距离。 **注意**:请注意,这两个点必须有相同的尺寸(即都在2d或3d空间)。 现在,为了计算这两个点之间的欧几里得距离,我们只需把它们夹在`dist()` 方法中。 ``` import math distance = math.dist(point_1, point_2) print(distance) ``` ``` 5.196152422706632 ``` ### 结论 *欧氏距离*是一个与*欧氏空间*中的系统有关的基本距离度量。 > 欧氏空间是你在数学课上熟悉的*经典几何空间*,通常被限定为3维。虽然,它也可以适用于任何非负的整数维。 > 欧几里得距离是欧几里得空间中两点之间的最短直线。 该指标在数据挖掘、机器学习和其他一些领域的许多情况下使用,是基本距离指标之一。