2015-05-09 12 views
5

Sto usando word2vec per rappresentare una piccola frase (da 3 a 4 parole) come un vettore univoco, aggiungendo ogni singola parola incorporata o calcolando la media degli embeddings di parole.word2vec, la somma o la media delle immersioni di parole?

Dagli esperimenti che ho fatto ottengo sempre la stessa somiglianza del coseno. Sospetto che abbia a che fare con i vettori di parole generati da word2vec che sono normati alla lunghezza unitaria (norma euclidea) dopo l'allenamento? o o ho un bug nel codice, o mi manca qualcosa.

Ecco il codice:

import numpy as np 
from nltk import PunktWordTokenizer 
from gensim.models import Word2Vec 
from numpy.linalg import norm 
from scipy.spatial.distance import cosine 

def pattern2vector(tokens, word2vec, AVG=False): 
    pattern_vector = np.zeros(word2vec.layer1_size) 
    n_words = 0 
    if len(tokens) > 1: 
     for t in tokens: 
      try: 
       vector = word2vec[t.strip()] 
       pattern_vector = np.add(pattern_vector,vector) 
       n_words += 1 
      except KeyError, e: 
       continue 
     if AVG is True: 
      pattern_vector = np.divide(pattern_vector,n_words) 
    elif len(tokens) == 1: 
     try: 
      pattern_vector = word2vec[tokens[0].strip()] 
     except KeyError: 
      pass 
    return pattern_vector 


def main(): 
    print "Loading word2vec model ...\n" 
    word2vecmodelpath = "/data/word2vec/vectors_200.bin" 
    word2vec = Word2Vec.load_word2vec_format(word2vecmodelpath, binary=True) 
    pattern_1 = 'founder and ceo' 
    pattern_2 = 'co-founder and former chairman' 

    tokens_1 = PunktWordTokenizer().tokenize(pattern_1) 
    tokens_2 = PunktWordTokenizer().tokenize(pattern_2) 
    print "vec1", tokens_1 
    print "vec2", tokens_2 

    p1 = pattern2vector(tokens_1, word2vec, False) 
    p2 = pattern2vector(tokens_2, word2vec, False) 
    print "\nSUM" 
    print "dot(vec1,vec2)", np.dot(p1,p2) 
    print "norm(p1)", norm(p1) 
    print "norm(p2)", norm(p2) 
    print "dot((norm)vec1,norm(vec2))", np.dot(norm(p1),norm(p2)) 
    print "cosine(vec1,vec2)",  np.divide(np.dot(p1,p2),np.dot(norm(p1),norm(p2))) 
    print "\n" 
    print "AVG" 
    p1 = pattern2vector(tokens_1, word2vec, True) 
    p2 = pattern2vector(tokens_2, word2vec, True) 
    print "dot(vec1,vec2)", np.dot(p1,p2) 
    print "norm(p1)", norm(p1) 
    print "norm(p2)", norm(p2) 
    print "dot(norm(vec1),norm(vec2))", np.dot(norm(p1),norm(p2)) 
    print "cosine(vec1,vec2)",  np.divide(np.dot(p1,p2),np.dot(norm(p1),norm(p2))) 


if __name__ == "__main__": 
    main() 

e qui è l'output:

Loading word2vec model ... 

Dimensions 200 
vec1 ['founder', 'and', 'ceo'] 
vec2 ['co-founder', 'and', 'former', 'chairman'] 

SUM 
dot(vec1,vec2) 5.4008677771 
norm(p1) 2.19382594282 
norm(p2) 2.87226958166 
dot((norm)vec1,norm(vec2)) 6.30125952303 
cosine(vec1,vec2) 0.857109242583 


AVG 
dot(vec1,vec2) 0.450072314758 
norm(p1) 0.731275314273 
norm(p2) 0.718067395416 
dot(norm(vec1),norm(vec2)) 0.525104960252 
cosine(vec1,vec2) 0.857109242583 

sto usando la similitudine del coseno come definito qui Cosine Similarity (Wikipedia). I valori per le norme e i prodotti punto sono davvero diversi.

Qualcuno può spiegare perché il coseno è lo stesso?

Grazie, David

risposta

7

Cosine misura l'angolo tra due vettori e non prende la lunghezza di entrambi vettore in considerazione. Quando dividi per la lunghezza della frase, stai semplicemente accorciando il vettore, non cambiando la sua posizione angolare. Quindi i risultati mi sembrano corretti.

+0

Grazie per la risposta. Ho trovato questa pagina che spiega che la similarità di Cosine, le correlazioni di Pearson e i coefficienti OLS possono essere tutti visualizzati come varianti sul prodotto interno (vale a dire, posizione e scala o qualcosa del genere). http://brenocon.com/blog/2012/03/cosine-similarity-pearson-correlation-and-ols-coefficients/ –