web-dev-qa-db-fra.com

Correspondance des mots et des vecteurs dans le modèle Word2Vec

J'ai eu la gensimWord2Vec implémentation de calculer quelques embarquements Word pour moi. Pour autant que je sache, tout s'est passé de façon fantastique. maintenant, je regroupe les vecteurs Word créés, dans l’espoir d’obtenir des regroupements sémantiques. 

Dans une prochaine étape, j'aimerais examiner les mots (plutôt que les vecteurs) contenus dans chaque grappe. C'est à dire. si j’ai le vecteur d’embeddings [x, y, z], je voudrais savoir quel mot ce vecteur représente. Je peux obtenir les mots/éléments de vocabulaire en appelant model.vocab et les vecteurs Word via model.syn0. Mais je ne pouvais pas trouver un endroit où ceux-ci sont explicitement appariés. 

C’était plus compliqué que prévu et j’ai le sentiment que je pourrais rater la façon évidente de le faire. Toute aide est appréciée!

Problème:

Faites correspondre les mots aux vecteurs d'incorporation créés par Word2Vec () - comment puis-je le faire? 

Mon approche:

Après avoir créé le modèle (code ci-dessous *), je voudrais maintenant faire correspondre les index attribués à chaque mot (au cours de la phase build_vocab()) avec la matrice de vecteurs sortie sous le nom model.syn0.

for i in range (0, newmod.syn0.shape[0]): #iterate over all words in model
    print i
    Word= [k for k in newmod.vocab if newmod.vocab[k].__dict__['index']==i] #get the Word out of the internal dicationary by its index
    wordvector= newmod.syn0[i] #get the vector with the corresponding index
    print wordvector == newmod[Word] #testing: compare result of looking up the Word in the model -- this prints True
  • Existe-t-il un meilleur moyen de le faire, par exemple en introduisant le vecteur dans le modèle pour correspondre au mot?

  • Est-ce que cela me donne même des résultats corrects?

* Mon code pour créer les vecteurs Word:

model = Word2Vec(size=1000, min_count=5, workers=4, sg=1)

model.build_vocab(sentencefeeder(folderlist)) #sentencefeeder puts out sentences as lists of strings

model.save("newmodel")

J'ai trouvé cette question qui est similaire mais qui n'a pas vraiment reçu de réponse. 

17
patrick

J'ai donc trouvé un moyen simple de procéder, où nmodel est le nom de votre modèle. 

#Zip the two lists containing vectors and words
zipped = Zip(nmodel.wv.index2Word, nmodel.wv.syn0)

#the resulting list contains `(Word, wordvector)` tuples. We can extract the entry for any `Word` or `vector` (replace with the Word/vector you're looking for) using a list comprehension:
wordresult = [i for i in zipped if i[0] == Word]
vecresult = [i for i in zipped if i[1] == vector]

Ceci est basé sur le code gensim . Pour les anciennes versions de gensim, vous devrez peut-être supprimer la variable wv après le modèle. 

5
patrick

Je cherchais depuis longtemps le mappage entre la matrice syn0 et le vocabulaire ... voici la réponse: utilisez model.index2Word qui est simplement la liste des mots dans le bon ordre!

Ce n'est pas dans la documentation officielle (pourquoi?) Mais on peut le trouver directement dans le code source: https://github.com/RaRe-Technologies/gensim/blob/3b9bb59dac0d55a1cd6ca8f984cead38b9cb0860/gensim/models/Word2vec.p L441

9
Arcyno

Si vous souhaitez uniquement mapper un Word sur un vector, vous pouvez simplement utiliser l'opérateur [], par exemple. model["hello"] vous donnera le vecteur correspondant à bonjour.

Si vous avez besoin de récupérer un mot à partir d'un vecteur, vous pouvez parcourir votre liste de vecteurs et rechercher une correspondance, comme vous le proposez. Cependant, c'est inefficace et non pas Pythonic. Une solution pratique consiste à utiliser la méthode similar_by_vector du modèle Word2vec, comme suit:

import gensim

documents = [['human', 'interface', 'computer'],
 ['survey', 'user', 'computer', 'system', 'response', 'time'],
 ['eps', 'user', 'interface', 'system'],
 ['system', 'human', 'system', 'eps'],
 ['user', 'response', 'time'],
 ['trees'],
 ['graph', 'trees'],
 ['graph', 'minors', 'trees'],
 ['graph', 'minors', 'survey']]

model = gensim.models.Word2Vec(documents, min_count=1)
print model.similar_by_vector(model["survey"], topn=1)

qui produit:

[('survey', 1.0000001192092896)]

où le nombre représente la similitude.

Cependant, cette méthode est toujours inefficace, car il lui reste à analyser tous les vecteurs Word pour rechercher le plus similaire. La meilleure solution à votre problème consiste à trouver un moyen de garder une trace de vos vecteurs pendant le processus de mise en cluster afin que vous n'ayez pas à compter sur des mappages inverses coûteux.

4
bpachev

Comme @bpachev l'a mentionné, gensim dispose d'une option de recherche par vecteur, à savoir similar_by_vector.

Cependant, il met en œuvre une recherche linéaire par force brute, c’est-à-dire calcule la similarité en cosinus entre un vecteur donné et les vecteurs de tous les mots du vocabulaire, et dégage les premiers voisins. Une autre option, comme mentionné dans l'autre answer consiste à utiliser un algorithme approximatif de recherche du plus proche voisin tel que FLANN.

Partage d'un résumé démontrant la même chose: https://Gist.github.com/kampta/139f710ca91ed5fabaf9e6616d2c762b

0
kampta