cosine_similarity输出全为1且维度不兼容问题排查求助
问题:计算电影标签平均Word2Vec向量余弦相似度时的异常问题
我尝试计算某部电影标签的平均Word2Vec向量与其他所有电影的平均Word2Vec向量的余弦相似度,但cosine_similarity的输出始终全为1,甚至传入相同电影向量时也是如此,同时还出现维度不兼容的错误,具体细节如下:
1. Word2Vec模型训练代码
model = gensim.models.Word2Vec(window=10, min_count=1, workers=8, vector_size=300, alpha=0.03, min_alpha=0.0007) model.build_vocab(flatten_corpus) # flatten_corpus为语料库 model.train(flatten_corpus, total_examples=model.corpus_count, epochs=10) embeddings = model.wv.get_normed_vectors()
2. 词嵌入输出示例
array([[-0.01744956, -0.11224882, 0.13236344, ..., 0.0972883 , 0.02966034, -0.04626285], [ 0.05841004, -0.00941145, -0.07332838, ..., -0.07433803, 0.02825699, -0.12789766], [ 0.10318288, -0.08702228, -0.14564443, ..., 0.1026295 , 0.01967871, 0.03213153], ..., [-0.03165161, 0.08460254, -0.05135883, ..., -0.00983593, 0.08976564, 0.01239256], [-0.04694653, 0.12579133, -0.03276197, ..., -0.02105372, 0.08431913, -0.0318971 ], [ 0.03841057, 0.03328352, -0.05580311, ..., 0.04187248, -0.03482581, -0.02766625]], dtype=float32)
3. 平均Word2Vec计算代码
ls = [] avg_embeddings = [] for i in range(len(flatten_corpus)): if len(flatten_corpus[i]) != 0: for j in range(len(flatten_corpus[i])): if len(flatten_corpus[j]) != 0: if len(flatten_corpus[i][j]) != 0: ls.append(model.wv[flatten_corpus[i][j]].tolist()) ls = list(chain.from_iterable(ls)) avg_embeddings.append(sum(ls)/len(flatten_corpus[i])) ls = []
4. 相似度计算代码及错误
执行以下代码时:
cosine_similarity(np.array(avg_embeddings[idx]).reshape(1, -1), np.array(avg_embeddings).reshape(1, -1))
出现维度不兼容错误:
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[702], line 1 ----> 1 cosine_similarity(np.array(avg_embeddings[idx]).reshape(1, -1), np.array(avg_embeddings).reshape(1, -1)) File ~/anaconda3/lib/python3.10/site-packages/sklearn/metrics/pairwise.py:1393, in cosine_similarity(X, Y, dense_output) 1358 """Compute cosine similarity between samples in X and Y. 1359 1360 Cosine similarity, or the cosine kernel, computes similarity as the (...) 1389 Returns the cosine similarity between samples in X and Y. 1390 """ 1391 # to avoid recursive import -> 1393 X, Y = check_pairwise_arrays(X, Y) 1395 X_normalized = normalize(X, copy=True) 1396 if X is Y: File ~/anaconda3/lib/python3.10/site-packages/sklearn/metrics/pairwise.py:180, in check_pairwise_arrays(X, Y, precomputed, dtype, accept_sparse, force_all_finite, copy) 174 raise ValueError( 175 "Precomputed metric requires shape " 176 "(n_queries, n_indexed). Got (%d, %d) " 177 "for %d indexed." % (X.shape[0], X.shape[1], Y.shape[0]) 178 ) 179 elif X.shape[1] != Y.shape[1]: -> 180 raise ValueError( 181 "Incompatible dimension for X and Y matrices: " 182 "X.shape[1] == %d while Y.shape[1] == %d" % (X.shape[1], Y.shape[1]) 183 ) 185 return X, Y ValueError: Incompatible dimension for X and Y matrices: X.shape[1] == 1 while Y.shape[1] == 4881
当传入两个参数均为avg_embeddings时,输出为:
array([[1.]]) # 预期应该输出4886个相似度值,对应总电影数量
问题分析与解决方法
核心错误点
平均向量计算逻辑完全错误:
- 内层循环错误使用
flatten_corpus[j]而非flatten_corpus[i][j],导致跨电影取词向量,完全打乱单部电影的标签集合。 - 用
chain.from_iterable(ls)把所有词向量的元素平铺成一维列表,后续sum(ls)是把所有数值相加,再除以电影标签数量,得到的不是300维的平均向量,而是一个标量(单一数值)。这直接导致avg_embeddings里的每个元素都是标量,而非300维向量。
- 内层循环错误使用
相似度计算的维度错误:
- 因为
avg_embeddings的元素是标量,所以np.array(avg_embeddings[idx]).reshape(1,-1)得到(1,1)的形状,而np.array(avg_embeddings).reshape(1,-1)是(1, 4881)的形状,维度不匹配引发错误。 - 传入两个
avg_embeddings时,cosine_similarity计算的是两个一维数组的自相似,自然得到1。
- 因为
修正后的平均向量计算代码
import numpy as np avg_embeddings = [] for movie_tags in flatten_corpus: if not movie_tags: # 跳过空标签集合 avg_embeddings.append(np.zeros(300)) # 用零向量填充空标签电影 continue # 收集当前电影所有标签的词向量(过滤不在词表中的标签) tag_vectors = [model.wv[tag] for tag in movie_tags if tag in model.wv] if not tag_vectors: # 处理所有标签都不在词表的情况 avg_embeddings.append(np.zeros(300)) continue # 对300维向量分别求均值,得到当前电影的平均向量 avg_vec = np.mean(tag_vectors, axis=0) avg_embeddings.append(avg_vec) # 转换为numpy数组方便后续计算 avg_embeddings = np.array(avg_embeddings)
修正后的相似度计算代码
计算某部电影(索引idx)与其他所有电影的余弦相似度:
from sklearn.metrics.pairwise import cosine_similarity # 取出目标电影的向量,形状为(1, 300) target_vec = avg_embeddings[idx].reshape(1, -1) # 计算与所有电影的相似度,结果形状为(1, 4886) similarities = cosine_similarity(target_vec, avg_embeddings) print(similarities)
额外说明
- 训练Word2Vec时使用了
get_normed_vectors(),得到的是归一化后的词向量,后续可以对平均向量再做归一化,确保余弦相似度计算的一致性。 - 处理空标签或标签不在词表的情况很重要,避免出现计算错误或缺失值。
内容的提问来源于stack exchange,提问作者YuvrajSingh
相关产品推荐
相关产品推荐

