不同余弦相似度函数对Word2Vec向量计算结果差异及实现问题
问题分析与解决思路
首先得明确两个核心概念的差异,这是你产生困惑的根源:
- 余弦相似度:公式为
cosθ = (x·y) / (||x|| * ||y||),范围在[-1, 1]之间,值越接近1表示两个向量越相似。Gensim的model.wv.similarity()返回的就是这个值。 - 余弦距离:通常定义为
1 - 余弦相似度,范围在[0, 2]之间,值越接近0表示越相似。Scipy的scipy.spatial.distance.cosine()返回的是这个结果。
你的自定义cosine(x,y)返回1.0,按照余弦距离的定义,这意味着对应的余弦相似度是0,但Gensim算出的是0.075,说明你的实现大概率存在问题,最常见的原因有两个:
1. 未对向量做L2归一化
Gensim的wv.similarity()内部会先对两个向量做L2归一化(即把向量缩放成单位向量,||x||=1,||y||=1),此时点积就等于余弦相似度。如果你的自定义函数没有做归一化,或者错误地跳过了范数计算步骤,就会得到完全偏离的结果。
比如如果你的函数直接计算1 - np.dot(x,y),当向量点积本身很小时(比如0.075),结果会接近1.0,这就和你看到的情况完全匹配。
2. 自定义函数的逻辑错误
这里给你两个和官方工具对齐的正确实现参考,你可以对比自己的代码排查问题:
正确的余弦相似度实现(和Gensim一致)
import numpy as np def cosine_similarity(x, y): # 先做L2归一化,和Gensim内部逻辑对齐 x_norm = x / np.linalg.norm(x) y_norm = y / np.linalg.norm(y) # 归一化后的点积等价于余弦相似度 return np.dot(x_norm, y_norm)
正确的余弦距离实现(和Scipy一致)
import numpy as np def cosine_distance(x, y): x_norm = x / np.linalg.norm(x) y_norm = y / np.linalg.norm(y) # 余弦距离 = 1 - 余弦相似度 return 1 - np.dot(x_norm, y_norm)
用这两个函数测试你的x和y:
cosine_similarity(x,y)应该和model.wv.similarity('amber','best')结果一致(约0.075)cosine_distance(x,y)应该返回1-0.075=0.925左右,而非1.0
你可以重点检查自己的cosine函数是否遗漏了归一化步骤,或者错误地简化了余弦计算的公式。
内容的提问来源于stack exchange,提问作者Art




