列出预训练模型中 spaCy 中最相似的词

sna*_*ack 7 python spacy

使用 Gensim,在我训练自己的模型后,我可以使用model.wv.most_similar('cat', topn=5)并获取cat向量空间中最接近的 5 个单词的列表。例如:

from gensim.models import Word2Vec
model = Word2Vec.load('mymodel.model')

In: model.wv.most_similar('cat', topn=5)
Out: ('kitten', .99)
     ('dog', .98)
     ...
Run Code Online (Sandbox Code Playgroud)

使用 spaCy,根据文档,我可以执行以下操作:

import spacy

nlp = spacy.load('en_core_web_md')
tokens = nlp(u'dog cat banana')

for token1 in tokens:
    for token2 in tokens:
        print(token1.text, token2.text, token1.similarity(token2))
Run Code Online (Sandbox Code Playgroud)

它给出了指定字符串中标记的相似性。但是通过文档和搜索,我无法弄清楚是否有一种 gensim 类型的方式来列出带有nlp = spacy.load('en_core_web_lg')或的预加载模型的所有相似词nlp = spacy.load('en_vectors_web_lg')。有没有办法做到这一点?

小智 6

我使用了安迪的回应,它工作正常但速度很慢。为了解决这个问题,我采用了下面的方法。

SpaCy 在后端使用余弦相似度来计算.similarity。因此,我决定word.similarity(w)用其优化的对应物替换。我使用的优化方法是cosine_similarity_numba(w.vector, word.vector),如下所示,它使用 Numba 库来加速计算。您应该用下面的行替换 most_similar 方法中的第 12 行。

by_similarity = sorted(queries, key=lambda w: cosine_similarity_numba(w.vector, word.vector), reverse=True)
Run Code Online (Sandbox Code Playgroud)

该方法的速度提高了 2-3 倍,这对我来说至关重要。

from numba import jit

@jit(nopython=True)
def cosine_similarity_numba(u:np.ndarray, v:np.ndarray):
    assert(u.shape[0] == v.shape[0])
    uv = 0
    uu = 0
    vv = 0
    for i in range(u.shape[0]):
        uv += u[i]*v[i]
        uu += u[i]*u[i]
        vv += v[i]*v[i]
    cos_theta = 1
    if uu != 0 and vv != 0:
        cos_theta = uv/np.sqrt(uu*vv)
    return cos_theta
Run Code Online (Sandbox Code Playgroud)

我在这篇文章中更详细地解释了它:如何在 SpaCy 中构建快速的“最相似词”方法


小智 5

它不是开箱即用的。但是,基于这个问题(https://github.com/explosion/spaCy/issues/276)这里有一个代码可以让它按你的意愿工作。

import spacy
import numpy as np
nlp = spacy.load('en_core_web_lg')

def most_similar(word, topn=5):
  word = nlp.vocab[str(word)]
  queries = [
      w for w in word.vocab 
      if w.is_lower == word.is_lower and w.prob >= -15 and np.count_nonzero(w.vector)
  ]

  by_similarity = sorted(queries, key=lambda w: word.similarity(w), reverse=True)
  return [(w.lower_,w.similarity(word)) for w in by_similarity[:topn+1] if w.lower_ != word.lower_]

most_similar("dog", topn=3)
Run Code Online (Sandbox Code Playgroud)

  • 难道你不应该迭代“nlp.vocab”而不是“word.vocab”中的所有单词吗? (2认同)