稀疏矩阵间的特特殊余弦

0 投票
1 回答
2337 浏览
提问于 2025-04-18 13:21

我正在尝试计算两个向量的余弦相似度。这两个向量(我们叫它们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 )

然后可以用这些明确的(或稠密的)表示来计算RipRjp的余弦相似度,

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 )

撰写回答