Python 带权文档的余弦相似性

Python 带权文档的余弦相似性,python,scikit-learn,cosine-similarity,trigonometry,Python,Scikit Learn,Cosine Similarity,Trigonometry,我试图找出两份文件的余弦相似性,如下所示: d1: [(0,1), (3,2), (6, 1)] d2: [(1,1), (3,1), (5,4), (6,2)] 其中,每个文档都是主题权重向量,其中主题是元组中的第一个元素,权重是第二个元素 我不知道在这种情况下,如何使用这种加权方案来计算余弦相似性?Python中是否有任何模块/包可以让我做这样的事情 一个非常简单的想法是创建一个权重向量,然后使用它来计算余弦距离(等于1-相似度): 通过快速查看,似乎没有现成的函数可以接受这种形式的输入。

我试图找出两份文件的余弦相似性,如下所示:

d1: [(0,1), (3,2), (6, 1)]
d2: [(1,1), (3,1), (5,4), (6,2)]
其中,每个文档都是主题权重向量,其中主题是元组中的第一个元素,权重是第二个元素


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

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


通过快速查看,似乎没有现成的函数可以接受这种形式的输入。您有两种选择,这取决于问题、数组的大小和其他因素。您可以将两个主题权重向量转换为稀疏scipy向量,然后使用sklearn的cosine_相似度(),也可以编写自己的cosine_相似度。我做后者的方法是将每个向量转换为dict(以便更快地查找),如下所示

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

是的,有python中的包,例如。下面我为您提供了一种手动方式:

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...

如果向量很长,或者有很多可能的主题,那么您希望保持它们稀疏,否则使它们密集是危险的。如果向量稀疏,并且有很多主题,则为True。@mdml-谢谢,我假设N是唯一主题的总数?我怎么能找到呢?主题的数量可能因情况而异,我可能需要一种方法来计算它们apriori@newdev14:完全正确,
N
是主题的数量。应该足够简单,例如,
max(d1+d2中的d为d[0])
Yes,或者参见travelingbones的答案/注释,其获得n个等级的方式类似,但公式中的主题数量是两个文档的总数,而不是唯一的主题数量…这是所需的。您可能的意思是: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,在中键入每行(或子行的每个元素),并让它对其求值,以便您可以看到代码在做什么。
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...