Euclidean distance 和 cosine similarity 是什么关系?
什么时候用哪个?
先弄清楚:每个概念是什么
- Euclidean distance
- 两点之间的直线距离,\(\|a - b\| = \sqrt{\sum_i (a_i - b_i)^2}\),方向和长短都管。 例:(0, 0) 到 (3, 4) 的距离是 5。
- Dot product
- \(a^\top b = \sum_i a_i b_i = \|a\|\,\|b\|\cos\theta\):长度和夹角乘在一起,分不开。
- Cosine similarity
- 只看两个向量的夹角,不管长短。同向为 1,垂直为 0,反向为 −1,tf-idf 这类非负向量只会落在 [0, 1]。 例:(1, 0) 和 (1, 1) 夹 45°,cosine = 0.707。
- L2 normalization
- 每个向量除以自己的长度,把所有点推到单位球面上,只留下方向。 例:(3, 4) 变成 (0.6, 0.8)。
- Cosine distance
- \(1 - \cos\theta\),方便塞进只认 distance 的算法,但它不是真正的 metric(见追问)。
30 秒回答
Expanding the square, ‖a − b‖² = ‖a‖² + ‖b‖² − 2aᵀb, and aᵀb = ‖a‖‖b‖cos θ. If both vectors are L2-normalized, this becomes ‖a − b‖² = 2 − 2cos θ, so squared Euclidean distance is a decreasing linear function of cosine similarity, and nearest-neighbor rankings are identical. Without normalization, Euclidean distance mixes vector length with angle, while cosine only looks at direction. So I'd use cosine, or normalize and then use Euclidean distance or the dot product, when the length is a nuisance, like document length for tf-idf vectors or text embeddings, and Euclidean distance when magnitude carries meaning, like physical coordinates.
推导
\(2 - 2\cos\theta\) 随 \(\cos\theta\) 单调递减,所以 cosine 最大的邻居就是 Euclidean 最近的邻居,排序完全一样。\(\cos = 1\) → 距离 0,\(\cos = 0\) → \(\sqrt2\),\(\cos = -1\) → 2。
没 normalize 时 \(\|a - b\|^2 = \|a\|^2 + \|b\|^2 - 2\|a\|\|b\|\cos\theta\),长度和夹角混在一起,排序可能不同。
什么时候用哪个
看向量的长度有没有意义。
- 一篇文档和它自己重复 5 遍,方向相同、长短不同,内容算一样 → cosine。
- tf-idf、文本 embedding 一般用 cosine:长度主要受文档长短、词频影响,和语义关系不大。
- 坐标、物理量这类大小本身有意义的数据 → Euclidean。推荐系统常用不 normalize 的 inner product,item 向量的长度会影响排序。
例:query \(q = (1, 1)\),两篇文档 \(d_1 = (5, 5)\)(同一个话题,只是更长)、\(d_2 = (1, 0)\)。
| Euclidean | cosine | normalize 后 \(\|\hat q - \hat d\|^2\) | |
|---|---|---|---|
| \(d_1 = (5, 5)\) | \(\sqrt{32} \approx 5.66\) | 1 | 0 |
| \(d_2 = (1, 0)\) | 1 | 0.707 | \(2 - 2 \times 0.707 = 0.586\) |
原始的 Euclidean 说 \(d_2\) 更近,cosine 说 \(d_1\) 更像。normalize 之后 Euclidean 也选 \(d_1\),数值正好等于 \(2 - 2\cos\)。
代码(NumPy)
A = X / np.linalg.norm(X, axis=1, keepdims=True) # L2 normalize
C = A @ A.T # cosine similarity
D2 = ((A[:, None] - A[None]) ** 2).sum(-1) # 平方 Euclidean
print(np.allclose(D2, 2 - 2 * C)) # True
必答点
- 展开:\(\|a - b\|^2 = \|a\|^2 + \|b\|^2 - 2a^\top b\),\(a^\top b = \|a\|\|b\|\cos\theta\)
- normalize 后 \(\|a - b\|^2 = 2 - 2\cos\theta\),nearest neighbor 排序完全一样
- 没 normalize:Euclidean 同时受长度和夹角影响,cosine 只看方向
- 长度是噪声(文本、embedding)→ cosine;长度有意义 → Euclidean
- 只支持 Euclidean / inner product 的工具:先 L2-normalize
追问
Cosine distance(1 − cos)是 metric 吗?
不是,triangle inequality 不成立。\(a = (1, 0)\)、\(b = (1, 1)/\sqrt2\)、\(c = (0, 1)\) 时 \(d(a, b) + d(b, c) = 0.29 + 0.29 = 0.59 < d(a, c) = 1\)。normalize 后的 Euclidean \(\sqrt{2 - 2\cos\theta}\) 是 metric。BallTree 这类靠 triangle inequality 剪枝的索引用不了 cosine distance,所以 sklearn 里 metric="cosine" 的 kNN 只能 brute force。
K-means 想按 cosine 聚类怎么办?
先 L2-normalize 再跑 K-means,assign 这一步就等于按 cosine 分。但簇内均值不再是单位向量,每轮把质心也重新 normalize,就是 spherical k-means。
向量检索(比如 FAISS)里怎么做 cosine?
建 inner product 索引,入库和查询前都 L2-normalize,最大 inner product 就是最大 cosine。也可以用 L2 索引,因为 \(\|x - y\|^2 = 2 - 2\langle x, y\rangle\)。
Cosine 和 Pearson correlation 什么关系?
Pearson 就是两个向量各自减去均值之后的 cosine。例:\(s = (1, 2, 3, 4)\)、\(t = (2, 1, 4, 5)\),cosine = 0.97,减均值后的 cosine = 0.85 = Pearson。所以 Pearson 不受平移和缩放影响,cosine 只不受缩放影响。
来源Murphy, PML1 §16.2.2(p.554,eq. 16.7–16.9)、§20.5.1.1(pp.706–707,eq. 20.141–20.142)· sklearn User Guide §8.8.1 Cosine similarity、euclidean_distances docstring · FAISS wiki: MetricType and distances