2. 向量距离度量:选对尺子,才能量准距离

做向量检索这些年,我最大的感触就是:距离度量选错了,后面的索引结构再精妙也白搭。说白了,你用什么尺子量距离,直接决定了哪些向量会被认为是“相似的”。

这一章咱们就把六种最常见的距离度量掰开揉碎讲清楚。我会从数学原理讲到适用场景,再穿插一些我在项目中踩过的坑。

核心观点:没有最好的距离度量,只有最合适的。选度量之前,先想清楚你的数据长什么样、业务要什么。

向量距离度量知识体系 距离度量 Lp 距离族 角度/内积族 集合/二进制族 欧氏距离 曼哈顿距离 余弦相似度 点积 Jaccard 汉明距离 连续向量 图像/音频 稀疏向量 推荐系统 文本/语义 归一化后 未归一化 推荐排序 集合数据 标签/分类 二进制向量 哈希/编码 选度量 = 选视角:数据特性决定度量选择

2.1 欧氏距离:最直观的"直线距离"

欧氏距离就是你在初中几何课上学过的两点间直线距离。公式很简单:

d(x, y) = sqrt(Σ(xi - yi)²)

说白了,就是把两个向量每个维度上的差值平方,加起来再开根号。

适用场景:

  • 连续型稠密向量,比如图像特征、音频特征
  • 各维度量纲一致的数据
  • 需要保留向量"大小"信息的场景

我的经验:做图像检索时,我习惯先用欧氏距离。因为它对"整体差异"敏感——两张图亮度不同但内容相似,欧氏距离会偏大。这时候我会考虑先做归一化。

2.2 余弦相似度:只看方向,不看大小

余弦相似度衡量的是两个向量之间的夹角。公式:

cos(θ) = (x · y) / (||x|| × ||y||)

结果范围在 [-1, 1] 之间。1 表示方向完全一致,-1 表示方向相反。

你想想看,文本向量化之后,文档长度差异很大,但内容可能很相似。这时候用欧氏距离就不太合适了——长文档和短文档的模长差异会干扰判断。余弦相似度正好解决这个问题。

适用场景:

  • 文本检索、语义相似度
  • 用户画像、推荐系统
  • 任何需要忽略向量模长的场景

注意:余弦相似度对零向量没定义。我在处理稀疏向量时遇到过这个问题——全零向量的模长为 0,除零错误直接崩了。记得加个判空处理。

2.3 曼哈顿距离:城市街区的走法

曼哈顿距离也叫 L1 距离。想象你在曼哈顿街头,不能穿楼而过,只能沿着街道走。公式:

d(x, y) = Σ|xi - yi|

它和欧氏距离的区别在哪?欧氏距离是"直线过去",曼哈顿距离是"沿着坐标轴走"。高维空间里,曼哈顿距离对异常值没那么敏感。

适用场景:

  • 稀疏向量、高维数据
  • 推荐系统中的协同过滤
  • 特征维度含义独立、可解释性强的场景

避坑指南:我曾经在一个推荐项目里用欧氏距离做协同过滤,结果效果很差。换成曼哈顿距离后,准确率提升了 12%。原因?用户评分数据是稀疏的,曼哈顿距离对缺失值更鲁棒。

2.4 点积:带方向的相似度

点积就是对应元素相乘再求和:

x · y = Σ(xi × yi)

点积同时考虑了方向和模长。两个向量方向越一致、模长越大,点积越大。

我个人习惯在推荐系统的排序阶段用点积。为什么?因为用户向量和物品向量的模长本身就包含了"偏好强度"的信息,点积能把这个信息保留下来。

适用场景:

  • 未归一化的向量
  • 推荐系统中的矩阵分解
  • 注意力机制中的 score 计算

小技巧:如果向量已经归一化到单位长度,点积和余弦相似度是等价的。很多向量数据库(比如 Milvus)内部会把余弦相似度转成点积来加速计算。

2.5 Jaccard 相似度:集合的交并比

Jaccard 相似度不是算向量坐标的,它算的是集合的重叠程度:

J(A, B) = |A ∩ B| / |A ∪ B|

范围 [0, 1]。0 表示没有交集,1 表示完全重合。

用在向量上时,通常先把向量二值化(比如用户有没有购买某商品),然后算交集大小除以并集大小。

适用场景:

  • 标签系统、分类数据
  • 购物篮分析
  • 文档去重(用 shingling 技术)

注意:Jaccard 对稀疏集合很敏感。两个用户都只买过 1 件商品,恰好相同,Jaccard 就是 1.0。这不一定代表他们兴趣一致。我一般会配合购买次数做加权处理。

2.6 汉明距离:二进制向位的差异计数

汉明距离统计的是两个等长字符串(或二进制向量)在对应位置上不同字符的个数。公式很简单:

d(x, y) = count of positions where xi ≠ yi

比如 10110 和 10010,只有第 3 位不同,汉明距离就是 1。

适用场景:

  • 二进制向量、哈希编码
  • 错误检测与纠正
  • LSH(局部敏感哈希)中的近邻搜索

我的实践:做近似最近邻搜索时,我常用 LSH 把浮点向量转成二进制哈希码,然后用汉明距离做快速筛选。速度能比浮点计算快一个数量级,代价是精度略有损失。

2.7 六种度量对比一览

度量 数学本质 取值范围 对模长敏感 典型场景
欧氏距离 L2 范数 [0, +∞) 是 图像、音频特征
余弦相似度 夹角余弦 [-1, 1] 否 文本、语义检索
曼哈顿距离 L1 范数 [0, +∞) 是 稀疏数据、协同过滤
点积 内积 (-∞, +∞) 是 推荐排序、注意力
Jaccard 交并比 [0, 1] 不适用 集合、标签数据
汉明距离 位差异计数 [0, d] 不适用 二进制哈希、纠错

2.8 实战选型建议

说了这么多,到底怎么选?我总结了几条经验:

  1. 先看数据类型:连续稠密向量优先考虑欧氏或余弦;稀疏向量试试曼哈顿;二进制向量用汉明;集合数据用 Jaccard。
  2. 再看业务需求:要区分"大小"(比如文档长度)就用欧氏或点积;只看"内容相似"就用余弦。
  3. 最后考虑性能:点积和曼哈顿计算比欧氏快(没有平方根);汉明距离可以用位运算加速。

我的习惯:不确定选哪个时,我会在数据集上跑一个小实验。随机采样 1000 条数据,分别用不同度量做 KNN,看召回率。数据会告诉你答案。