稀疏矩阵间的特特殊余弦
我正在尝试计算两个向量的余弦相似度。这两个向量(我们叫它们Ri和Rj)是用户对物品i和j的评分,所以它们通常是稀疏的(因为通常只有少数用户会对特定物品进行评分)。这两个向量有50000行,但只有0.1%的值是非零的。
计算余弦相似度时,需要考虑共同评分的用户评分。比如,如果Ri和Rj是两个scipy.sparse.csc矩阵,它们的值是:
Ri = [ 1, 2, 0, 0, 3, 4] Rj = [ 0, 1, 0, 3, 5, 2]
那么共同评分的结果是:
Ri' = [ 0, 2, 0, 0, 3, 4] Rj' = [ 0, 1, 0, 0, 5, 2]
所以余弦相似度应该是:
inner(Ri', Rj') / (|Ri'| * |Rj'|)
我想问的是,有没有一种高效的方法(最好是不使用循环)来计算两个矩阵中哪些位置的值都是非零的?谢谢!
1 个回答
0
我不太确定你在问哪个矩阵,但假设你有两个原始数组,存放在变量里,
Ri = [ 1, 2, 0, 0, 3, 4]; Rj = [ 0, 1, 0, 3, 5, 2]
接下来,你可以构建共同评分,并计算余弦相似度,
import numpy as np
Rip = np.array( [ i if j != 0 else 0 for i,j in zip(Ri,Rj) ] )
Rjp = np.array( [ j if i != 0 else 0 for i,j in zip(Ri,Rj) ] )
如果你不想明确使用for循环,可以用map来代替,
Rip = map( lambda x,y: 0 if y == 0 else x, Ri, Rj )
Rjp = map( lambda x,y: 0 if x == 0 else y, Ri, Rj )
然后可以用这些明确的(或稠密的)表示来计算Rip
和Rjp
的余弦相似度,
cos_sim = float( np.dot( Rip, Rjp ) ) / np.sqrt( np.dot( Rip,Rip ) * np.dot( Rjp,Rjp ) )
如果你不想明确存储完整的数组,可以使用scipy.sparse
将向量存储为稀疏的单行(列)矩阵。请注意,如果这样做,np.dot
将不再有效,你应该使用稀疏矩阵的dot
方法。
from scipy.sparse import csr_matrix
# make single column/row sparse matrix reps of Rip
row = np.array( [ i for (i,x) in enumerate(Rip) if x != 0 ] )
col = np.zeros( row.size, dtype=np.int32 )
dat = np.array( [ x for (i,x) in enumerate(Rip) if x != 0 ] )
Rip_col_mat = csr_matrix( (dat,(row,col) ) )
Rip_row_mat = csr_matrix( (dat,(col,row) ) )
# make single column/row sparse matrix reps of Rjp
row = np.array( [ i for (i,x) in enumerate(Rjp) if x != 0 ] )
col = np.zeros( row.size, dtype=np.int32 )
dat = np.array( [ x for (i,x) in enumerate(Rjp) if x != 0 ] )
Rjp_col_mat = csr_matrix( (dat,(row,col) ) )
Rjp_row_mat = csr_matrix( (dat,(col,row) ) )
现在我们可以这样计算余弦相似度,
inner = Rip_row_mat.dot( Rjp_col_mat ).data
Rip_m = np.sqrt( Rip_row_mat.dot( Rip_col_mat ).data )
Rjp_m = np.sqrt( Rjp_row_mat.dot( Rjp_col_mat ).data )
cos_sim = inner / ( Rip_m * Rjp_m )