我已经下载了en_core_web_lg
模型并试图找到两个句子之间的相似性:
nlp = spacy.load('en_core_web_lg')
search_doc = nlp("This was very strange argument between american and british person")
main_doc = nlp("He was from Japan, but a true English gentleman in my eyes, and another one of the reasons as to why I liked going to school.")
print(main_doc.similarity(search_doc))
哪个返回值很奇怪:
0.9066019751888448
这两个句子的相似度不应 90%。
为什么会这样?我是否需要添加某种额外的词汇表以使相似性结果更合理?
答案 0 :(得分:5)
向量相似性的Spacy documentation解释了其基本概念:
每个单词都有一个向量表示法,可以通过上下文嵌入(Word2Vec)进行学习,并根据语料库对其进行训练,如文档中所述。
现在,完整句子的单词嵌入只是所有不同单词的平均值。如果您现在有很多单词在语义上位于同一区域(例如,“ he”,“ was”,“ this”,...等填充词)和附加词汇“ cancel out”,那么您最终可能会与您的情况相似。
正确的问题是您可以做什么:从我的角度来看,您可以想出一个更复杂的相似性度量。由于search_doc
和main_doc
具有其他信息,例如原始句子,因此您可以通过长度差罚分来修改向量,或者尝试比较句子的较短部分,然后计算成对相似度(然后再次,问题是要比较哪些部分。
遗憾的是,目前还没有一种简单的方法可以简单地解决此问题。
答案 1 :(得分:5)
Spacy通过平均单词嵌入来构造句子嵌入。由于在一个普通的句子中有很多毫无意义的单词(称为stop words),所以您得到的结果很差。您可以这样删除它们:
search_doc = nlp("This was very strange argument between american and british person")
main_doc = nlp("He was from Japan, but a true English gentleman in my eyes, and another one of the reasons as to why I liked going to school.")
search_doc_no_stop_words = nlp(' '.join([str(t) for t in search_doc if not t.is_stop]))
main_doc_no_stop_words = nlp(' '.join([str(t) for t in main_doc if not t.is_stop]))
print(search_doc_no_stop_words.similarity(main_doc_no_stop_words))
或仅保留名词,因为它们具有最多的信息:
doc_nouns = nlp(' '.join([str(t) for t in doc if t.pos_ in ['NOUN', 'PROPN']))
答案 2 :(得分:5)
如其他人所述,您可能要使用通用句子编码器或推断。
对于Universal Sentence编码器,您可以安装用于管理TFHub包装的预构建SpaCy模型,因此只需安装带有pip的软件包即可使矢量和相似性按预期工作。
您可以按照此存储库中的说明操作(我是作者)https://github.com/MartinoMensio/spacy-universal-sentence-encoder-tfhub
安装模型:pip install https://github.com/MartinoMensio/spacy-universal-sentence-encoder-tfhub/releases/download/en_use_md-0.2.0/en_use_md-0.2.0.tar.gz#en_use_md-0.2.0
加载并使用模型
import spacy
# this loads the wrapper
nlp = spacy.load('en_use_md')
# your sentences
search_doc = nlp("This was very strange argument between american and british person")
main_doc = nlp("He was from Japan, but a true English gentleman in my eyes, and another one of the reasons as to why I liked going to school.")
print(main_doc.similarity(search_doc))
# this will print 0.310783598221594
答案 3 :(得分:1)
正如@dennlinger所指出的那样,Spacy的句子嵌入只是各个单词向量嵌入的平均值。因此,如果您的句子中带有否定词,例如“好”和“坏”,则它们的向量可能会相互抵消,从而导致上下文嵌入效果不佳。如果您的用例特定于获取句子嵌入,则应尝试使用以下SOTA方法。
Google的通用句子编码器:https://tfhub.dev/google/universal-sentence-encoder/2
Facebook的推断编码器:https://github.com/facebookresearch/InferSent
我已经尝试了这两种嵌入,并在大多数情况下为您提供了良好的效果,并使用词嵌入作为构建句子嵌入的基础。
干杯!