如何使用Python的gensim实现word2vec模型计算句子相似度

145 投票
14 回答
131015 浏览
提问于 2025-04-17 20:31

根据Gensim Word2Vec的介绍,我可以使用gensim这个包里的word2vec模型来计算两个词之间的相似度。

比如:

trained_model.similarity('woman', 'man') 
0.73723527

不过,word2vec模型在预测句子相似度方面效果不太好。我发现了在gensim中有一个LSI模型可以用来计算句子相似度,但似乎这个模型和word2vec不能结合使用。我手头每个句子的语料长度都不长(少于10个词)。所以,有没有什么简单的方法可以实现这个目标呢?

14 个回答

18

一旦你计算出两组词向量的总和,你应该计算这两个向量之间的余弦值,而不是它们的差值。余弦值可以通过先把这两个向量进行点积,然后再进行归一化来计算。所以,词的数量并不是一个影响因素。

28

你可以使用“词移动距离”算法。这里有一个关于WMD的简单介绍

#load word2vec model, here GoogleNews is used
model = gensim.models.KeyedVectors.load_word2vec_format('../GoogleNews-vectors-negative300.bin', binary=True)
#two sample sentences 
s1 = 'the first sentence'
s2 = 'the second text'

#calculate distance between two sentences using WMD algorithm
distance = model.wmdistance(s1, s2)

print ('distance = %.3f' % distance)

附注:如果你在导入pyemd库时遇到错误,可以使用以下命令来安装它:

pip install pyemd
53

如果你在使用word2vec这个工具,你需要先计算每个句子或文档中所有单词的平均向量,然后再用这些向量之间的余弦相似度来比较它们的相似性。

import numpy as np
from scipy import spatial

index2word_set = set(model.wv.index2word)

def avg_feature_vector(sentence, model, num_features, index2word_set):
    words = sentence.split()
    feature_vec = np.zeros((num_features, ), dtype='float32')
    n_words = 0
    for word in words:
        if word in index2word_set:
            n_words += 1
            feature_vec = np.add(feature_vec, model[word])
    if (n_words > 0):
        feature_vec = np.divide(feature_vec, n_words)
    return feature_vec

计算相似度的方法:

s1_afv = avg_feature_vector('this is a sentence', model=model, num_features=300, index2word_set=index2word_set)
s2_afv = avg_feature_vector('this is also sentence', model=model, num_features=300, index2word_set=index2word_set)
sim = 1 - spatial.distance.cosine(s1_afv, s2_afv)
print(sim)

> 0.915479828613
83

既然你在用gensim,那你可能应该使用它的doc2vec功能。doc2vec是word2vec的一个扩展,适用于短语、句子和文档层面。这个扩展其实很简单,详细介绍可以参考这里:

http://cs.stanford.edu/~quocle/paragraph_vector.pdf

gensim的好处在于它直观、快速且灵活。最棒的是,你可以从官方的word2vec页面获取预训练的词向量,而gensim的Doc2Vec模型的syn0层也可以直接使用,这样你就可以用这些高质量的向量来初始化词向量!

GoogleNews-vectors-negative300.bin.gz(链接在Google Code上)

我认为gensim绝对是将句子嵌入向量空间中最简单(对我来说也是最好的)工具。

除了上面Le和Mikolov的论文中提到的方法,还有其他句子转向量的技术。斯坦福大学的Socher和Manning无疑是这个领域最著名的研究者之一。他们的研究基于组合性原则——句子的语义来自于:

1. semantics of the words

2. rules for how these words interact and combine into phrases

他们提出了一些这样的模型(越来越复杂),用于如何利用组合性来构建句子级别的表示。

2011年 - 展开递归自编码器(相对简单。如果感兴趣可以从这里开始)

2012年 - 矩阵-向量神经网络

2013年 - 神经张量网络

2015年 - 树形LSTM

他的论文都可以在socher.org找到。其中一些模型是可以使用的,但我还是推荐使用gensim的doc2vec。首先,2011年的URAE模型并不是特别强大。此外,它是预训练的,适合处理新闻类数据。提供的代码不允许你重新训练网络,也不能更换不同的词向量,所以你只能用2011年Turian的预训练词向量。这些向量的水平肯定比不上word2vec或GloVe。

我还没有使用树形LSTM,但它看起来非常有前景!

总结一下:是的,使用gensim的doc2vec。但其他方法确实存在!

99

你问的问题其实挺复杂的。要计算句子之间的相似度,我们需要先建立一个句子的语法模型,理解句子中相同的结构,比如“他昨天走到商店”和“昨天,他走到商店”是一样的意思。我们还要找出不仅在代词和动词上有相似之处,还要在专有名词上找相似,分析很多真实文本中的统计关系等等。

你可以尝试一个最简单的方法——虽然我不知道这个方法效果如何,也肯定不是最佳的结果。首先,你可以去掉所有的“停用词”(像“the”、“an”等这些对句子意义贡献不大的词),然后对两个句子中的词使用word2vec技术。接着,把一个句子的词向量加起来,再把另一个句子的词向量也加起来,然后找出这两个总和之间的差异。通过加总而不是逐个比较单词,你至少不会受到单词顺序的影响。不过,这种方法在很多方面都会失败,根本算不上好办法(而且解决这个问题的好方法几乎总是需要一些自然语言处理、机器学习和其他聪明的技巧)。

所以,简单来说,没有简单的方法可以做到这一点(至少要做到好)。

撰写回答