2015-05-09 2 views
5

Я использую word2vec для представления небольшой фразы (от 3 до 4 слов) в качестве уникального вектора либо путем добавления каждого отдельного вложения слова, либо путем вычисления среднего значения вложений слов.word2vec, сумма или среднее слово вложения?

Из проведенных экспериментов я всегда получаю одинаковое сходство с косинусом. Я подозреваю, что это связано с тем, что слова векторы, генерируемые word2vec, нормируются на единицу длины (евклидова норма) после обучения? или либо у меня есть ошибка в коде, либо я что-то упустил.

Вот код:

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() 

и вот результат:

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 

Я использую косинус сходство, как определено здесь Cosine Similarity (Wikipedia). Значения норм и точечных произведений действительно различны.

Может ли кто-нибудь объяснить, почему косинус одинаковый?

Спасибо, Дэвид

ответ

7

косинус измеряет угол между двумя векторами и не принимает длину либо вектора во внимание. Когда вы делите на длину фразы, вы просто сокращаете вектор, не изменяя его углового положения. Поэтому ваши результаты выглядят правильно для меня.

+0

Благодарим вас за ответ. Я нашел эту страницу, которая объясняет, что сходство Косина, корреляции Пирсона и коэффициенты OLS можно рассматривать как варианты на внутреннем продукте (т. Е. Местоположение и масштаб, или что-то в этом роде). http://brenocon.com/blog/2012/03/cosine-similarity-pearson-correlation-and-ols-coeictions/ –

Смежные вопросы