【问题标题】:cosine similarity of documents with weights具有权重的文档的余弦相似度
【发布时间】:2016-11-03 17:53:41
【问题描述】:

我试图找出两个文档的余弦相似度,如下所示:

d1: [(0,1), (3,2), (6, 1)]
d2: [(1,1), (3,1), (5,4), (6,2)]

其中每个文档是一个主题权重向量,其中主题是元组中的第一个元素,权重是第二个元素

我不确定在这种情况下如何使用这种加权方案计算余弦相似度? Python中是否有任何模块/包可以让我做这样的事情?

【问题讨论】:

    标签: python scikit-learn cosine-similarity trigonometry


    【解决方案1】:

    快速浏览一下,似乎没有现成的函数可以接受该表单的输入。您有两个选择,这取决于问题、数组的大小和其他因素。您可以将两个主题权重向量中的每一个转换为稀疏 scipy 向量,然后使用 sklearn 的 cosine_similarity (http://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.cosine_similarity.html) 或者您可以编写自己的 cosine_similarity。我会做后者的方式是将每个向量转换为这样的字典(以便更快地查找)。

    import math
    
    def vect_to_topic_weight(vector):
       return {a:b for a,b in vector}
    
    def norm(vector):
       return math.sqrt(sum(vector[k]**2 for k in vector.iterkeys()))
    
    def dot(a,b):
       return sum(a[k]*b.get(k,0) for k in a.iterkeys())
    
    # returns the cosine_similarity, with inputs as topic_weight dicts
    def cosine_similarity(a, b):
       return  dot(a,b) / float(norm(a)*norm(b))
    

    【讨论】:

      【解决方案2】:

      是的,python 中有包,例如scikit-learn's cosine sim. documentation here。下面我给你一个手动的方法:

      import numpy as np
      
      d1 = dict([(0,1), (3,2), (6, 1)]) 
      d2 = dict([(1,1), (3,1), (5,4), (6,2)])
      
      l = max(d1.keys() + d2.keys()) + 1 ## Number of topics observed 
      
      v1 = np.zeros((l,))
      for i in xrange(l):
          if i in d1.keys():
              v1[i] = d1[i]
      
      v2 = np.zeros((l,))
      for i in xrange(l):
          if i in d2.keys():
              v2[i] = d2[i]
      
      ## now v1 and v2 are 1-d np arrays representing your docs. 
      
      v1 = v1/np.sqrt(np.dot(v1,v1)) ## normalize
      v2 = v2/np.sqrt(np.dot(v2,v2)) ## normalize
      
      cos_sim = np.dot(v1,v2)  ## should get .348155...
      

      【讨论】:

      • 谢谢,但公式中的主题数是两个文档的总数,而不是唯一的主题数......这是需要的
      • 你可能的意思是:max(d1.keys() + d2.keys()) + 1?
      • 您最后的评论正是我所拥有的。为了清楚起见, max( d1.keys()+d2.keys() ) = max( [0,3,6] +[1,3,5,6] ) = max( [0,3,6, 1, 3,5,6]) = 6。我们想要 +1 b/c,主题数为 7(0 是一个主题)。
      • 作为一般规则,使用 ipython,并输入每一行(或子行的每个元素),并让它对其进行评估,以便您查看代码在做什么。
      【解决方案3】:

      一个非常简单的想法是创建一个权重向量,然后使用scipy.spatial.distance.cosine 计算余弦距离(等于1-相似度):

      In [1]: from scipy.spatial.distance import cosine
      In [2]: import numpy as np
      In [3]: d1 = [(0,1), (3,2), (6, 1)]
      In [4]: d2 = [(1,1), (3,1), (5,4), (6,2)]
      In [5]: def get_weights(d):
         ...:     w = [ 0. ] * N
         ...:     for i, weight in d:
         ...:         w[i] = weight
         ...:     return np.array(w)
         ...: 
      
      In [6]: w1 = get_weights(d1)
      In [7]: w2 = get_weights(d2)
      In [8]: 1-cosine(w1, w2)
      Out[8]: 0.3481553119113957
      

      【讨论】:

      • 如果向量很长或者有很多可能的主题,那么你希望它们保持稀疏 - 否则使它们变得密集是危险的。
      • 是的,假设向量是稀疏的,并且有很多主题。
      • @mdml - 谢谢,我假设 N 是唯一主题的总数?我怎么能找到那个?主题的数量可能因情况而异,我可能需要一种方法来先验地计算它们
      • @newdev14:完全正确,N 是主题的数量。应该足够简单,例如max( d[0] for d in d1 + d2 )
      • 是的,或者看看 travelbones answer/cmets 有类似的方法来获得 N
      猜你喜欢
      • 2019-03-14
      • 2014-02-25
      • 2015-05-31
      • 2015-05-07
      • 2014-02-25
      • 2020-01-25
      • 2020-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多