余弦相似性产生'nan'值

时间:2015-11-11 13:40:19

标签: python numpy sparse-matrix similarity cosine-similarity

我正在为稀疏向量计算余弦相似矩阵,而预期为浮点数的元素似乎是'nan'。

'visits'是一个稀疏矩阵,显示每个用户访问过每个网站的次数。这个矩阵的形状为1 500 000 x 1500,但我使用coo_matrix()。tocsc()将其转换为稀疏矩阵。

任务是找出网站有多相似,所以我决定计算每两个网站之间的余弦指标。

这是我的代码:

cosine_distance_matrix = np.ndarray(shape = (visits.shape[1], visits.shape[1]))

def norm(x):
return np.sqrt(
    x.T.dot(x)
)

for i in range(0, visits.shape[1]):
  for k in range(0, i + 1):
    normi_normk = norm(visits[:,i]) * norm(visits[:,k])
    cosine_distance_matrix[i,k] = visits[:,i].T.dot(visits[:, k])/normi_normk
    cosine_distance_matrix[k, i] = cosine_distance_matrix[i, k]

print cosine_distance_matrix

这就是我的成就! O_O

[[  1.  nan  nan ...,  nan  nan  nan]
 [ nan   1.  nan ...,  nan  nan  nan]
 [ nan  nan   1. ...,  nan  nan  nan]
 ..., 
 [ nan  nan  nan ...,   1.  nan  nan]
 [ nan  nan  nan ...,  nan   1.  nan]
 [ nan  nan  nan ...,  nan  nan   1.]]

这个程序运行了3个小时......这样的垃圾是什么原因而不是漂浮数?

1 个答案:

答案 0 :(得分:0)

尝试:

def norm(x):
    return np.sqrt((x.T*x).A)

我构建了一个较小的样本visits矩阵,并使用您的代码计算cosine_distance_matrix。我的对角线为1s,对角线上有很多nan。我选择其中一个nan项,并查看相应的i,k计算。

In [690]: normi_normk = norm(visits[:,i]) * norm(visits[:,k])
In [691]: normi_normk
Out[691]: 
<1x1 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in Compressed Sparse Column format>
In [692]: normi_normk.A
Out[692]: array([[ 18707.57953344]])

visits是一个稀疏矩阵,因此visits[:,i]也是稀疏矩阵(1列)。您的norm函数返回1x1稀疏矩阵。

对于这一对,此dot为0,但它仍然是1x1稀疏矩阵:

In [718]: visits[:,i].T.dot(visits[:, k])
Out[718]: 
<1x1 sparse matrix of type '<class 'numpy.int32'>'
    with 0 stored elements in Compressed Sparse Column format>

这些稀疏矩阵的划分也很稀疏 - nan

In [717]: visits[:,i].T.dot(visits[:, k])/normi_normk
Out[717]: matrix([[ nan]])

但如果我将normi_normk更改为标量或密集数组,我会得到0

In [722]: visits[:,i].T.dot(visits[:, k])/normi_normk.A
Out[722]: matrix([[ 0.]])

所以我们必须将它从matrix/matrix除法改为涉及密集数组或标量的东西。它可以通过各种方式进行更改。重写norm以正确处理稀疏矩阵是一个。

另外我建议使用:

(visits[:,i].T*visits[:, k]).A/normi_normk

这样两个部门的条款都很密集。

另一种可能性是使用visits[:,i].Avisits[:,k].A,因此内循环计算是使用密集数组而不是这些矩阵完成的。

请注意,我没有做任何高级或特殊的事情。我刚刚详细检查了一个问题计算,并找到了nan的来源。

我还建议使用np.zeros来初始化数组。我只在正常ndarrayzerosones不起作用时才使用empty

cosine_distance_matrix = np.zeros((visits.shape[1], visits.shape[1]))

总体而言,最好避免在ik上进行循环,使用矩阵产品等做任何事情。但是这个修复程序可以帮助你。