J'utilise spaCy dans le cadre d'une solution de modélisation de sujet et j'ai une situation où j'ai besoin de mapper un vecteur de mot dérivé au mot "le plus proche" ou "le plus similaire" dans un vocabulaire de vecteurs de mots.
Je vois que gensim a une fonction (WordEmbeddingsKeyedVectors.similar_by_vector) pour calculer cela, mais je me demandais si spaCy avait quelque chose comme ça pour mapper un vecteur à un mot dans son vocabulaire (nlp.vocab)?
3 Réponses :
Après un peu d'expérimentation, j'ai trouvé une fonction scikit (cdist dans scikit.spatial.distance) qui trouve un vecteur "proche" dans un espace vectoriel du vecteur d'entrée.
# Imports from scipy.spatial import distance import spaCy # Load the spacy vocabulary nlp = spacy.load("en_core_web_lg") # Format the input vector for use in the distance function # In this case we will artificially create a word vector from a real word ("frog") # but any derived word vector could be used input_word = "frog" p = np.array([nlp.vocab[input_word].vector]) # Format the vocabulary for use in the distance function ids = [x for x in nlp.vocab.vectors.keys()] vectors = [nlp.vocab.vectors[x] for x in ids] vectors = np.array(vectors) # *** Find the closest word below *** closest_index = distance.cdist(p, vectors).argmin() word_id = ids[closest_index] output_word = nlp.vocab[word_id].text # output_word is identical, or very close, to the input word
Un mot d'avertissement sur cette réponse. Traditionnellement, la similarité de mots (dans gensim, spacy et nltk) utilise la similitude cosinus tandis que par défaut, le cdist de scipy utilise la distance euclidienne. Vous pouvez obtenir la distance cosinus qui n'est pas la même chose que la similitude, mais elles sont liées. Pour dupliquer le calcul de gensim, changez votre appel cdist comme suit:
import spacy nlp = spacy.load("en_core_web_md") x = nlp("man") y = nlp("king") print(x.similarity(y)) print(x.similarity(x))
Cependant, vous devriez également noter que scipy mesure la distance cosinus qui est "en arrière" par rapport à la similarité cosinus où "cosinus dist" = 1 - cos x (x est l'angle entre les vecteurs), donc pour faire correspondre / dupliquer les nombres de gensim, vous devez soustraire votre réponse de un (et bien sûr, prenez l'argument MAX - les vecteurs similaires sont plus proches de 1). C'est une différence très subtile mais qui peut causer beaucoup de confusion.
Des vecteurs similaires devraient avoir une grande similitude (près de 1), tandis que la distance est petite (proche de zéro).
La similarité cosinus peut être négative (ce qui signifie que les vecteurs ont des directions opposées) mais leur DISTANCE sera positive (comme la distance devrait l'être).
source: https://docs.scipy.org/ doc / scipy / reference / generated / scipy.spatial.distance.cdist.html
également pour faire de la similitude dans spacy est le suivant:
distance.cdist(p, vectors, metric='cosine').argmin()
x.similarity
a été assez rapide pour que je puisse parcourir tous les mots du vocabulaire pour un petit nombre de cas.
Oui, spacy a une méthode API pour le faire, tout comme KeyedVectors.similar_by_vector:
import numpy as np import spacy nlp = spacy.load("en_core_web_lg") your_word = "king" ms = nlp.vocab.vectors.most_similar( np.asarray([nlp.vocab.vectors[nlp.vocab.strings[your_word]]]), n=10) words = [nlp.vocab.strings[w] for w in ms[0][0]] distances = ms[2] print(words) ['King', 'KIng', 'king', 'KING', 'kings', 'KINGS', 'Kings', 'PRINCE', 'Prince', 'prince']
(les mots ne sont pas correctement normalisés dans sm_core_web_lg
, mais vous pourrait jouer avec d'autres modèles et observer une sortie plus représentative).