0.写在前面
| 术语 | 含义 | 是否用于两向量比较 |
|---|---|---|
| L2 范数(L2 norm) | 单个向量的长度:∣x∣2|\mathbf{x}|_2∣x∣2 | ❌ |
| L2 距离(L2 distance) | 两向量之差的 L2 范数:∣x−y∣2|\mathbf{x} - \mathbf{y}|_2∣x−y∣2 | ✅ |
| 欧几里得距离(Euclidean distance) | 同上 | ✅ |
在嵌入空间中度量两个向量的"距离"时,应使用"欧几里得距离",而它在数值上等于这两个向量之差的 L2 范数
1.基本原理
欧几里得距离就是"两个点在连续空间中的直线距离"。
在 2D 平面中:
两点越近 → 越相似
两点越远 → 差异越大
这也是我们日常生活中对"距离"的最自然理解。
1.1 核心定义
欧几里得距离源于欧几里得空间 (Euclidean Space),这是一个满足欧几里得几何公理的n维向量空间。
对于n维空间中的两个点(向量) A=(a1,a2,...,an)A=(a_1,a_2,...,a_n)A=(a1,a2,...,an) 和 B=(b1,b2,...,bn)B=(b_1,b_2,...,b_n)B=(b1,b2,...,bn),欧几里得距离 的数学定义为:
d(A,B)=(a1−b1)2+(a2−b2)2+...+(an−bn)2=∑i=1n(ai−bi)2 d(A,B)=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+...+(a_n-b_n)^2} = \sqrt{\sum_{i=1}^{n}(a_i-b_i)^2} d(A,B)=(a1−b1)2+(a2−b2)2+...+(an−bn)2 =i=1∑n(ai−bi)2
低维空间的直观解释
- 1维空间 (数轴):两点 aaa 和 bbb 的距离为 ∣a−b∣|a-b|∣a−b∣,即绝对值。
- 2维空间 (平面直角坐标系):两点 (x1,y1)(x_1,y_1)(x1,y1) 和 (x2,y2)(x_2,y_2)(x2,y2) 的距离为 (x1−x2)2+(y1−y2)2\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}(x1−x2)2+(y1−y2)2 ,对应勾股定理。
- 3维空间 (立体坐标系):两点 (x1,y1,z1)(x_1,y_1,z_1)(x1,y1,z1) 和 (x2,y2,z2)(x_2,y_2,z_2)(x2,y2,z2) 的距离为 (x1−x2)2+(y1−y2)2+(z1−z2)2\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}(x1−x2)2+(y1−y2)2+(z1−z2)2 。
2.欧式距离的标准化
欧式距离的标准化,是在计算欧几里得距离之前或之后,对特征维度或距离值进行尺度校正,使不同维度或不同样本的距离具有可比性。消除不同特征维度上量纲和数值尺度差异对欧氏距离计算造成的扭曲性影响。
而标准化的本质是将所有特征映射到统一的数值尺度。
为什么欧式距离必须标准化?
欧几里得距离默认假设:
- 各维度 同量纲
- 各维度 同尺度
- 各维度 同等重要
不标准化 = 数值大的维度"支配一切"
2.1 标准化的三种主流形式(非常重要)
① 特征级标准化(最常见、最推荐)
在算欧氏距离 之前,先对每一维做标准化。
Z-score 标准化
将每个特征(维度)的数值转换为均值为 0、标准差为 1的标准正态分布,消除量纲和数值范围的影响。
xi′=xi−μiσix_i'=\frac{x_i-\mu_i}{\sigma_i}xi′=σixi−μi
然后:
d(x,y)=∑i(xi′−yi′)2d(x,y)=\sqrt{\sum_i (x_i'-y_i')^2}d(x,y)=∑i(xi′−yi′)2
📌 这是最经典、最常用的"欧式距离标准化"。
其中:
- μ\muμ:该特征维度的均值 (μ=1n∑i=1nxi\mu = \frac{1}{n}\sum_{i=1}^n x_iμ=n1∑i=1nxi);
- σ\sigmaσ:该特征维度的标准差 (σ=1n−1∑i=1n(xi−μ)2\sigma = \sqrt{\frac{1}{n-1}\sum_{i=1}^n (x_i - \mu)^2}σ=n−11∑i=1n(xi−μ)2 )。
Min-Max 标准化
将每个特征的数值映射到**[0, 1]**(或指定区间如[-1, 1])的范围内,是一种线性缩放。
$
x_i'=\frac{x_i-\min_i}{\max_i-\min_i}
$
其中:
- min(X)\min(X)min(X):该特征维度的最小值;
- max(X)\max(X)max(X):该特征维度的最大值。
若需映射到其他区间 [a,b][a, b][a,b],则公式为:
xi′=a+(xi−min(X))×(b−a)max(X)−min(X)x_i' = a + \frac{(x_i - \min(X))×(b - a)}{\max(X) - \min(X)}xi′=a+max(X)−min(X)(xi−min(X))×(b−a)
适合:
- 有明确上下界
- 无明显异常值
② 距离级标准化(弱标准化)
在距离算完之后再缩放:
d′(x,y)=d(x,y)maxd或d(x,y)−μdσd d'(x,y)=\frac{d(x,y)}{\max d} \quad \text{或} \quad \frac{d(x,y)-\mu_d}{\sigma_d} d′(x,y)=maxdd(x,y)或σdd(x,y)−μd
📌 这不改变距离关系,只改变数值范围
③ 协方差标准化(最"正统"的形式)
这实际上就是:
马哈拉诺比斯距离(Mahalanobis Distance)
$
d(x,y)=\sqrt{(x-y)^T \Sigma^{-1}(x-y)}
$
📌 可以理解为:
- 对欧氏空间做了 旋转 + 拉伸
- 自动完成标准化 + 去相关
3.优缺点适用场景
| 特点 | 说明 |
|---|---|
| ✅ 核心优点 | 直观易懂 :符合人类对"距离"的直觉 数学性质优良 :连续、可微、满足三角不等式 广泛支持 :几乎所有库 适合低维稠密数据 :如坐标、传感器、嵌入向量 |
| ❌ 主要缺点 | 维度灾难 :高维下区分度急剧下降(>50 维慎用).在高维空间:点之间距离趋于相等,区分度下降 量纲敏感 :必须标准化(如 StandardScaler) 忽略方向信息 :仅关注绝对差异,不反映语义方向(此时余弦更优) 不适合稀疏向量 :TF-IDF,One-hot欧氏距离会被 0 淹没 假设各维独立同权:无法建模特征相关性,无法表达"不等重要" |
| 🛠️ 典型使用场景 | K-Means 聚类 :默认使用欧氏距离分配点到中心 KNN 分类/回归 :找 L2 最近的 k 个邻居 计算机视觉特征匹配 :SIFT、ORB 特征描述子 地理坐标距离:GPS 点(短距离) |
4.框架选型
虽然多个库都支持欧氏距离计算,但在性能、易用性、扩展性上有显著差异。
| 库名 | 函数/方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| NumPy | np.linalg.norm(a - b) |
✅ 极简、高效 ✅ 无额外依赖 | ❌ 不支持批量优化 ❌ 无 GPU 加速 | 小规模实验、教学 |
| SciPy | scipy.spatial.distance.euclidean |
✅ 专为距离设计 ✅ 支持多种距离 | ❌ 单点计算慢 ❌ 批量需循环 | 单次精确计算 |
| scikit-learn | sklearn.metrics.pairwise_distances |
✅ 支持批量矩阵 ✅ 自动并行 ✅ 与 ML pipeline 无缝集成 | ❌ 内存占用高(全距离矩阵) | 中小规模聚类/KNN |
| **FAISS **(Facebook) | faiss.IndexFlatL2 |
✅ 十亿级向量 ANN 搜索 ✅ GPU 支持 ✅ 内存高效 | ❌ 学习成本高 ❌ 需编译安装 | 大规模向量检索(推荐系统、CV) |
| PyTorch / TensorFlow | torch.cdist, tf.norm(a-b) |
✅ 自动微分 ✅ GPU 加速 ✅ 适合训练 | ❌ 主要用于训练阶段 | 深度度量学习(Triplet Loss 等) |
🥇 哪个框架"实现得最好"?
取决于你的数据规模和任务类型:
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 小规模实验(< 10k 向量) | ✅ NumPy / SciPy | 简单直接,无需额外依赖 |
| 机器学习 pipeline(K-Means, KNN) | ✅ scikit-learn | 与 KMeans, NearestNeighbors 无缝集成 |
| 大规模近似搜索(> 1M 向量) | ✅ FAISS | 工业界标准,支持 L2 精确/近似搜索 |
| 深度学习训练 | ✅ PyTorch / TensorFlow | 支持梯度回传,GPU 加速 |
💡 综合推荐:
- 通用首选 :
scikit-learn(平衡易用性与功能)- 超大规模 :
FAISS- 研究/原型 :
NumPy
6.使用
1. NumPy(最基础)
python
import numpy as np
a, b = np.array([1, 2]), np.array([4, 6])
dist = np.linalg.norm(a - b) # → 5.0
2. scikit-learn(批量计算)
python
from sklearn.metrics import pairwise_distances
X = [[1, 2], [3, 4]]
Y = [[0, 0], [5, 5]]
D = pairwise_distances(X, Y, metric='euclidean')
# 返回 2x2 距离矩阵
3. FAISS(大规模检索)
python
import faiss
import numpy as np
# 构建 100 万条 128 维向量
d = 128
nb = 1_000_000
xb = np.random.random((nb, d)).astype('float32')
# 创建 L2 索引(精确搜索)
index = faiss.IndexFlatL2(d)
index.add(xb)
# 查询
xq = np.random.random((10, d)).astype('float32')
D, I = index.search(xq, k=5) # 返回每查询的 5 个最近邻及其 L2 距离
4. PyTorch(可微分)
python
import torch
a = torch.tensor([[1.0, 2.0]], requires_grad=True)
b = torch.tensor([[4.0, 6.0]])
dist = torch.cdist(a, b, p=2) # 可用于 loss 计算