距离取决于所选几何
从范数推导距离,在 L1、L2 和 L-无穷范数下比较一个微型最近邻搜索,并调试 AI 系统中的度量选择。
当工单路由器、推荐系统或检索系统寻找“最近的”已存示例时,它其实做出了一个几何选择。当每个坐标分别作出贡献时最近的点,可能会输给另一个按平方长度组合坐标时更近的点。算法并没有变得不一致;变的是“接近”的含义。
学完本课后,你将能够从范数推导距离,在多种度量下计算一个小型最近邻排序,并识别让这个排序有意义的预处理和并列处理决策。
学习目标: 从范数推导距离并比较最近邻。
本课建立在第 040 课:L1、L2 与 L-无穷范数对大小的不同理解之上;该课介绍了衡量单个向量大小的几种方式。官方 Mathematics for Machine Learning 一书的第 3.3 节提供了数学参考。这里的数据集、计算、代码、可视化和练习题均为原创。
最近的点始于位移
设 和 是 中的两个点。每个坐标都是一个特征位置; 是特征数量。要询问 距离 多远,先逐坐标相减:
这个差是一个位移向量。它表示一个点在每个坐标上需要移动多少才能到达另一个点。交换相减顺序会改变位移的符号,但两种情况下范数给出的大小相同,因为 。
这些名称描述了不同的移动规则。L1 通常称为曼哈顿距离,把每个坐标的移动量相加。L2 衡量位移的直线长度。L-无穷范数只关注单个坐标中最大的移动量。使用其中一种度量的模型,就是在声明哪些移动类型应被视为代价高昂。
第 3.3 节的参考资料还通过 将内积与范数联系起来。在通常的点积下,这就是欧几里得范数,因此 。一个有用的细节是,距离构造适用于任何范数:L1 是有效范数,即使它在通常的实向量空间意义下不是由内积诱导的,它仍会诱导出有效度量。
为什么必须先相减
距离通过一个位移来比较两个位置,而不是比较它们各自大小的差。例如,若 且 ,两个点的 L2 范数都是 ,但
计算 会抹去这两个点在竖直方向相距两个单位这一事实。安全的思维口诀是先相减,再应用所选范数。
同一组点可以得到不同的最近邻
考虑查询点 ,以及二维表示中的三条候选记录。坐标特意取为较小的无量纲数:它们表示经过某种特征表示后的值,而不是普遍适用的相似性概念。
| 点 | 描述 | 坐标 |
|---|---|---|
| 轴向占优的情况 | ||
| 均衡的情况 | ||
| 混合的情况 |
排序会改变,是因为不同范数会奖励不同形状的位移。在这里,L1 偏好轴向占优的点 ,因为它的坐标总移动量最小。L2 选中 :它的两个坐标组合出的直线线段比 的对角线和 的长水平线段都短。L-无穷范数选中 ,因为没有任何单个坐标移动超过 。
一次查询,三张邻居图
| 候选点 | 坐标 | L1绝对移动量之和 | L2直线长度 | L-无穷范数最大的坐标移动量 |
|---|---|---|---|---|
| A 轴向占优 | (6, 0) | 6.000排名 1 | 6.000排名 3 | 6.000排名 3 |
| B 均衡 | (4, 4) | 8.000排名 3 | 5.657排名 2 | 4.000排名 1 |
| C 混合 | (5, 2) | 7.000排名 2 | 5.385排名 1 | 5.000排名 2 |
| 最近的两个候选点 | A → C | C → B | B → C | |
圆圈内的数字表示该度量下的排名。虚线指向最近的候选点;前两个排名带有轮廓,因此这张图不依赖颜色来传达信息。
在 L1 下,顺序为 A、C、B;在 L2 下,顺序为 C、B、A;在 L-无穷范数下,顺序为 B、C、A。每个面板中的查询点都位于原点。
无需阅读 SVG,表格和排名标签就已经呈现了结论。可视化额外提供了一个空间线索:度量改变时,虚线的终点会改变,而坐标本身保持不变。
透明的 NumPy 搜索
NumPy 的 numpy.linalg.norm 文档 展示了这里所需的两个控制项:ord 选择范数阶数,axis 选择要进行归约的坐标轴。因此,包含三行候选点的批次可以通过从每一行中减去查询点,再分别对每行做归约来处理。
下面的代码复现了推导过程,而不是把它藏在最近邻对象中。代码已用 NumPy 执行;打印出的顺序与上面的例子相同。
import numpy as np
query = np.array([0.0, 0.0])
points = np.array([[6.0, 0.0], [4.0, 4.0], [5.0, 2.0]])
labels = np.array(["A", "B", "C"])
difference = points - query
for name, order in [("L1", 1), ("L2", 2), ("L-infinity", np.inf)]:
distances = np.linalg.norm(difference, ord=order, axis=1)
ranked = np.argsort(distances, kind="stable")
print(
f"{name}: "
+ ", ".join(f"{labels[i]}={distances[i]:.3f}" for i in ranked)
)
L1: A=6.000, C=7.000, B=8.000
L2: C=5.385, B=5.657, A=6.000
L-infinity: B=4.000, C=5.000, A=6.000
有三个独立操作值得注意:
points - query在应用任何范数之前执行相减。axis=1为每行计算一个范数,因此每个候选点得到一个距离。argsort把距离变成排序;范数本身并不决定如何处理相等的值。
对于更大的数据集,scikit-learn 的 NearestNeighbors 类封装了同样的思想。它的 metric="minkowski" 设置使用参数 p,其中 对应 L1, 对应 L2;它的 kneighbors 方法同时返回距离和索引。当搜索需要集成进模型管道时,估计器很有用;但 NumPy 版本更适合调试,因为每个中间数组都可见。
对于这个确切例子,等价的搜索配置是:
from sklearn.neighbors import NearestNeighbors
search = NearestNeighbors(n_neighbors=2, metric="minkowski", p=2)
search.fit(points)
distances, indices = search.kneighbors(query.reshape(1, -1))
nearest_labels = labels[indices[0]]
把 p 改为 1 或 np.inf 会改变几何,同时保持数据和 的值不变。API 并没有让度量选择消失;它只是把这个选择明确写成参数。
会改变答案的边界条件
只有在特征空间、度量和搜索策略都明确之后,距离才是精确的。以下情况最容易让一个小型最近邻演示产生误导。
并列是信息,不是噪声
设 、,以及 。两个候选点都有
如果 ,数学给出的是并列,而不是唯一胜者。生产系统应声明确定性的次级键,返回所有并列候选点,或采用适合其应用的策略。NumPy 代码中的 stable 排序让重复运行具有可复现性,但并不能证明排在第一位的并列行更相似。
相同点的距离为零
如果 ,那么 ,每个范数都会给出 。这是有效的精确匹配,不是错误。不过,在训练集查找中,对同一个已拟合集合查询一行数据,可能会把该行自身作为最近邻。在解释结果之前,先决定自匹配是否有用;一个碰巧与已存行重复的外部查询仍应得到距离零。
特征缩放是几何的一部分
假设一个坐标是以美元计的年收入,另一个是从零到十的计数。仅仅因为数值单位更大,美元坐标就可能支配 L1 或 L2 距离。标准化、重新缩放或分配领域权重都会改变几何,而不是一个无关紧要的前置步骤。任何依赖数据的缩放规则都应在训练数据上拟合,并对查询使用同一规则,否则邻居图可能从评估集泄露信息。
距离和余弦相似度回答不同问题
距离比较两个点之间的位移,因此包含它们的位置和大小。余弦相似度则在归一化长度后比较方向。对于 和 ,
因为两个向量的方向完全相同,而
嵌入检索系统可能在“匹配”意味着方向时偏好余弦相似度。对尺度敏感的应用可能偏好由范数诱导的距离。没有一种选择普遍正确;而且余弦相似度还需要针对零向量制定单独策略,因为零向量的方向没有定义。
高维需要测量,而不是口号
在某些高维数据分布中,最近距离和最远距离可能变得越来越接近,使排序的区分度降低。Beyer、Goldstein、Ramakrishnan 和 Shaft 在他们关于最近邻的论文中描述了特定条件下的这种距离集中结果。这个结果提醒我们注意数据和工作负载假设,并不是说每个嵌入空间都会变得无用。在责怪搜索算法之前,应检查邻居距离间隔,在留出查询上验证度量,并考虑表示中是否包含许多无关坐标。
下一课将分离出距离有意与长度混合的方向比较:第 044 课《角度与余弦相似度》。当该课的翻译集上线后,Math for AI 英文课程页面将显示它。
检验理解
Question 1
对于 x = (5, −2) 和 y = (1, 1),计算位移以及 L1、L2 和 L-无穷范数距离。
Show the step-by-step solution
先减去两个点:。对这一个位移应用每个范数。L1 是
。L2 是 sqrt(4² + (−3)²) = sqrt(16 + 9) = 5
。L-无穷范数是最大的绝对坐标,。三个距离分别是 7、5 和 4。
Question 2
为什么 ||x||₂ − ||y||₂ 不是 x 与 y 之间距离的一般公式?请用 x = (1, 1) 和 y = (1, −1) 说明。
Show the step-by-step solution
两个单独的长度都是 和 ,所以它们的差为零。实际位移为 ,其 L2 范数为 。距离必须先相减,因为它衡量的是连接两个位置的向量,而不是它们到原点距离的差。
Question 3
使用 q = (0, 0)、A = (6, 0)、B = (4, 4) 和 C = (5, 2),在 L-无穷范数下哪两个候选点最近?请展示三个相关距离。
Show the step-by-step solution
减去 后得到候选点坐标。L-无穷范数距离保留最大的绝对坐标:、,以及 。将 4、5 和 6 排序后, 排第一, 排第二,因此两个邻居的结果是 。
Question 4
在 L1 下,q = (0, 0)、u = (1, 1) 和 v = (2, 0) 并列。并列距离是多少,k = 1 的实现必须决定什么?
Show the step-by-step solution
计算每个点相对于原点的位移。对 ,L1 给出 ;对 ,给出 。因此并列距离为 2。 的实现必须选择一种策略:返回两个候选点并让后续步骤解决并列,使用有文档记录的次级键,或采用应用规则。数组顺序可能让输出具有确定性,但不会让某个点在数学上更近。
Question 5
如果查询点 x 和存储点 y 都是 (2, −1),那么它们在每个范数下的距离是多少?为什么这个结果有意义?
Show the step-by-step solution
位移为 。每个范数都会把零向量映射为零,因此对于 L1、L2 和 L-无穷范数,。这就是不可分辨同一点性质:相同点没有位移。它作为精确匹配是有意义的,不过在训练集上搜索时,可能需要明确的自匹配策略。
Question 6
为什么未经缩放的特征可能支配距离?用 L2 距离比较 q = (0, 0)、a = (1, 100) 和 b = (2, 0)。
Show the step-by-step solution
位移为 和 。它们的 L2 距离分别是 和 。第二个坐标让 看起来远得多,尽管它的第一个坐标更近。重新缩放或标准化特征可以让各坐标的贡献更可比,但该预处理规则必须在训练数据上拟合,并一致地重复使用。
Question 7
对于 x = (1, 1) 和 y = (10, 10),为什么余弦相似度可以是 1,而 L2 距离却不是 0?
Show the step-by-step solution
点积为 。长度为 和 ,所以余弦相似度为 :两个方向完全一致。距离保留了大小差异。位移为 ,因此 。这两个度量回答的是不同的相似性问题。
Question 8
在 np.linalg.norm(points − query, ord=2, axis=1) 中,当 points 的形状为 (number_of_points, number_of_features) 时,axis=1 表示什么?
Show the step-by-step solution
points − query
的每一行是一个候选位移,每一列是一个特征坐标。设置 axis=1 告诉
NumPy 沿每行的列进行归约。因此结果是每个候选点一个 L2 值,形状为
(number_of_points,)
。沿错误的轴归约会把候选点混在一起,或者返回每个特征一个值,而不是可用的邻居排序。