
距离关心两个向量“隔多远”,余弦相似度关心两个向量“方向像不像”。 它们让模型能做搜索、推荐、分类和聚类
欧氏距离(Euclidean Distance)其实就是我们日常生活中最熟悉的 “直线距离”。它衡量的是两点之间的最短路径长度。

余弦相似度通过计算两个向量之间的夹角余弦值来衡量它们的相似性。
余弦值越接近1,夹角越小,说明两个向量越相似; 余弦值越接近-1,夹角越大,说明两个向量越不相似; 余弦值为0时,两个向量正交,表示它们之间没有相关性。
在计算余弦相似度时,我们只关注向量之间的夹角,而不考虑它们的长度。 因此,即使两个向量的长度不同,只要它们同向,余弦相似度依旧能够达到 1。


• A⋅B 表示向量 A 和向量 B 的点积。
• ||A|| 代表向量 A 的长度(模)。
• ||B|| 代表向量 B 的长度(模)。
• θ 是两个向量之间的夹角

上面提到向量的夹角,与向量长度无关,但公式里面为什么会出现模呢?还得去计算模?
向量的“模”(长度)和“方向”是捆绑存储在一个坐标里的。比如向量 A = (3, 4):
• 它的模长是 5 (3平方+4平方)再开根
• 它的方向是 53.1°
在计算机眼里,它就是一个数组 [3, 4],模和方向是混在一起的二进制数字。
你没法写一行代码说“把模去掉,只留方向”,因为数字 3 既贡献了方向,也贡献了长度。
如果你直接拿 [3, 4] 去算点积,结果里必然混着长度的影响。所以,我们必须通过数学运算把“长度”单独提取出来。
第一步(分子:计算点积):先让两个向量发生完整的交互。此时,A的长度、B的长度、以及它们的夹角,三者全部被混在一起,揉成了一个数值(点积)。 第二步(分母:除以模长的乘积):既然点积里混杂了“A的长度 × B的长度 × 夹角”,那我就在外面强行除以“A的长度 × B的长度”。
相当于:
(∣∣A∣∣×∣∣B∣∣×cosθ) / ∣∣A∣∣×∣∣B∣∣ = cosθ
因为你无法凭空忽略模长,你只能用模长来抵消自身。
• 如果你不计算分母 ∣∣A∣∣×∣∣B∣∣,你得到的就是带长度的点积,大向量永远欺负小向量。
• 你计算分母,不是为了“看重”模长,恰恰是为了 “利用”模长去“消除”模长。
在编程中不调用自带的 Math.cos()函数,实在令人惊讶。 这是因为该函数是直接计算出夹角的余弦值,而无需先求出夹角本身。 如果使用 Math.cos(),我们就需要先用诸如 Math.acos()之类的反三角函数来求出角度,这不仅没有必要,而且计算成本更高。
早期的实践归纳(启发式): 在早期的信息检索(如 TF-IDF、LSA 潜在语义分析)中,工程师们发现:如果把文档变成词频向量,用余弦相似度来匹配,效果出奇的好。这完全是实践归纳出来的经验法则。人们发现高维空间中的“几何邻近性”恰好对应了人类的“语义相关性”。
后期的理论证明(统计学习理论): 到了 Word2Vec 和深度学习时代,这不再仅仅是经验。学者们(如 Mikolov, Bengio 等)通过分布式假设(Distributional Hypothesis)——“上下文相似的词,语义相似”——给出了理论解释。
随后,大量的数学证明表明:通过最大化预测上下文的概率(如 Skip-gram 的负采样目标函数),模型实际上是在隐式地分解词共现矩阵(如 PMI 矩阵)。
这就从理论上证明了:为什么优化这个损失函数,最终会让相似的词在向量空间中靠近。
How does cosine similarity work?