如何使用gensim的word2vec模型和python计算句子相似度

时间:2014-03-02 16:04:54

标签: python gensim word2vec

根据Gensim Word2Vec,我可以使用gensim包中的word2vec模型来计算2个单词之间的相似度。

e.g。

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

然而,word2vec模型无法预测句子相似性。我发现在gensim中具有句子相似性的LSI模型,但是,似乎不能与word2vec模型结合。我所拥有的每个句子的语料库长度不是很长(短于10个单词)。那么,有没有简单的方法来实现这个目标呢?

13 个答案:

答案 0 :(得分:76)

这实际上是一个非常具有挑战性的问题。计算句子相似度需要建立句子的语法模型,理解等效结构(例如“他昨天走到商店”和“昨天,他走到商店”),不仅在代词和动词中找到相似性,而且在专有名词,在许多真实文本例子中找到统计共现/关系等。

你可以尝试的最简单的事情 - 虽然我不知道这会有多好,而且肯定不能给你最好的结果 - 首先要删除所有“停止”字样(像“the”这样的字样) ,“an”等不会对句子增加太多意义)然后对两个句子中的单词运行word2vec,总结一个句子中的向量,总结另一个句子中的向量,然后找到总和之间的差异。通过总结它们而不是做一个单词差异,你至少不会受到单词顺序的影响。话虽如此,这将在很多方面失败,并且无论如何都不是一个好的解决方案(尽管这个问题的好解决方案几乎总是涉及一些NLP,机器学习和其他聪明)。

所以,简短的回答是,不,没有简单的方法可以做到这一点(至少不要做得好)。

答案 1 :(得分:65)

由于您正在使用gensim,因此您应该使用它的doc2vec实现。 doc2vec是word2vec对短语,句子和文档级别的扩展。这是一个非常简单的扩展,在这里描述

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

Gensim很好,因为它直观,快速,灵活。最棒的是你可以从官方的word2vec页面中获取预训练的单词嵌入,并且暴露了gensim的Doc2Vec模型的syn0层,这样你就可以使用这些高质量的向量来嵌入单词嵌入!

GoogleNews-vectors-negative300.bin.gz

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

还有其他的句子对矢量技术,而不是Le& Mikolov的论文如上。斯坦福大学的Socher和Manning肯定是这一领域最着名的研究人员之一。他们的工作基于组合原则 - 句子的语义来自:

1. semantics of the words

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

他们已经提出了一些这样的模型(变得越来越复杂),以便如何使用组合来构建句子级表示。

2011 - unfolding recursive autoencoder(非常相对简单。如果感兴趣,请从这里开始)

2012 - matrix-vector neural network

2013 - neural tensor network

2015 - Tree LSTM

他的论文全部可在socher.org上找到。其中一些模型可用,但我仍然推荐gensim的doc2vec。首先,2011 URAE并不是特别强大。此外,它还预先配备了适用于解释新闻数据的权重。他提供的代码不允许您重新训练网络。你也不能交换不同的单词向量,所以你要坚持使用2011年来自Turian的pre-word2vec嵌入。这些载体肯定不在word2vec或GloVe的水平上。

Haven还没有使用Tree LSTM,但看起来很有希望!

tl; dr是的,请使用gensim的doc2vec。但其他方法确实存在!

答案 2 :(得分:29)

如果您使用的是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

答案 3 :(得分:22)

您可以使用Word Mover的距离算法。这是一个easy description about 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)

P.s。:如果您遇到有关导入pyemd库的错误,可以使用以下命令安装它:

pip install pyemd

答案 4 :(得分:17)

计算两组单词向量的总和后,应该在向量之间取余弦,而不是差异。可以通过将两个向量的点积归一化来计算余弦。因此,字数不是一个因素。

答案 5 :(得分:8)

我使用以下方法,效果很好。 你首先需要运行一个POSTagger然后过滤你的句子来摆脱停用词(决定因素,连词,......)。我推荐TextBlob APTagger。 然后通过取句子中每个单词向量的平均值来构建word2vec。 n_similarity method in Gemsim word2vec通过允许传递两组单词进行比较来完成这一点。

答案 6 :(得分:8)

我想更新现有的解决方案,以帮助那些计算句子语义相似性的人。

第1步:

使用gensim加载合适的模型,并计算句子中单词的单词向量,并将它们存储为单词列表

第2步: 计算句子向量

句子之间的语义相似度的计算很难,但最近一篇名为" A SIMPLE BUT TOUGH-TO-BEAT BASELINE FOR SENTENCE EMBEDDINGS"提出了一种简单的方法,通过计算句子中单词向量的加权平均值,然后去除其第一主成分上的平均向量的投影。这里的单词w的权重为a /(a + p(w) a)是一个参数而p(w)是(估计的)词频,称为平滑逆频率。这种方法表现得更好。

使用SIF(平滑反频率)计算句子向量的简单代码已经给出了本文提出的方法here

第3步: 使用sklearn cosine_similarity为句子加载两个向量并计算相似度。

这是计算句子相似度的最简单有效的方法。

答案 7 :(得分:6)

documentation中有一个函数可以获取单词列表并比较它们的相似之处。

s1 = 'This room is dirty'
s2 = 'dirty and disgusting room' #corrected variable name

distance = model.wv.n_similarity(s1.lower().split(), s2.lower().split())

答案 8 :(得分:3)

我尝试过以前答案提供的方法。它起作用,但它的主要缺点是句子越长,相似性越大(计算相似度我使用任意两个句子的两个平均嵌入的余弦得分),因为词越多,语义效果越积极。将被添加到句子中。

我认为我应该改变主意并使用句子嵌入代替this paperthis中的研究。

答案 9 :(得分:3)

Gensim paragraph embedding实现了名为 Doc2Vec 的模型。

作为IPython笔记本提供了不同的教程:

另一种方法将依赖于 Word2Vec 移词器的距离(WMD),如本教程所示:

另一种解决方案是依靠平均向量:

[None,150,3]

最后,如果您可以运行Tensorflow,则可以尝试: https://tfhub.dev/google/universal-sentence-encoder/2

答案 10 :(得分:3)

如果不使用Word2Vec,我们还有其他模型可以使用BERT进行嵌入。 以下是参考链接 https://github.com/UKPLab/sentence-transformers

pip install -U sentence-transformers

from sentence_transformers import SentenceTransformer
import scipy.spatial

embedder = SentenceTransformer('bert-base-nli-mean-tokens')

# Corpus with example sentences
corpus = ['A man is eating a food.',
          'A man is eating a piece of bread.',
          'The girl is carrying a baby.',
          'A man is riding a horse.',
          'A woman is playing violin.',
          'Two men pushed carts through the woods.',
          'A man is riding a white horse on an enclosed ground.',
          'A monkey is playing drums.',
          'A cheetah is running behind its prey.'
          ]
corpus_embeddings = embedder.encode(corpus)

# Query sentences:
queries = ['A man is eating pasta.', 'Someone in a gorilla costume is playing a set of drums.', 'A cheetah chases prey on across a field.']
query_embeddings = embedder.encode(queries)

# Find the closest 5 sentences of the corpus for each query sentence based on cosine similarity
closest_n = 5
for query, query_embedding in zip(queries, query_embeddings):
    distances = scipy.spatial.distance.cdist([query_embedding], corpus_embeddings, "cosine")[0]

    results = zip(range(len(distances)), distances)
    results = sorted(results, key=lambda x: x[1])

    print("\n\n======================\n\n")
    print("Query:", query)
    print("\nTop 5 most similar sentences in corpus:")

    for idx, distance in results[0:closest_n]:
        print(corpus[idx].strip(), "(Score: %.4f)" % (1-distance))

其他链接 https://github.com/hanxiao/bert-as-service

答案 11 :(得分:2)

Facebook研究小组发布了一个名为InferSent的新解决方案 结果和代码在Github上发布,请检查其回购。太棒了我打算使用它。 https://github.com/facebookresearch/InferSent

他们的论文 https://arxiv.org/abs/1705.02364 抽象: 许多现代的NLP系统都将词嵌入作为基本功能,而词嵌入以前是在大型语料库上以无监督的方式进行训练的。然而,为更大的文本块(例如句子)获得嵌入的努力并没有那么成功。学习句子的无监督表示的几种尝试还没有达到令人满意的性能,因此不能被广泛采用。在本文中,我们展示了使用斯坦福自然语言推理数据集的监督数据训练的通用句子表示在各种传输任务上如何始终能够胜过诸如SkipThought向量之类的无监督方法。就像计算机视觉如何使用ImageNet获取特征然后将其转移到其他任务一样,我们的工作往往表明自然语言推理是否适合将学习转移到其他NLP任务。我们的编码器是公开可用的。

答案 12 :(得分:0)

您可以将一个句子的单词向量加在一起。然后将两个句子向量的余弦相似度作为两个句子的相似度。我认为这是最简单的方法。