余弦相似度优化实现

5

我正在尝试理解这段优化代码,用于查找用户矩阵之间的余弦相似度。

def fast_similarity(ratings,epsilon=1e-9):
    # epsilon -> small number for handling dived-by-zero errors
    sim = ratings.T.dot(ratings) + epsilon
    norms = np.array([np.sqrt(np.diagonal(sim))])
    return (sim / norms / norms.T)

如果 ratings =
           items           
     u  [
     s    [1,2,3]
     e    [4,5,6]
     r    [7,8,9] 
     s  ]

norms将等于= [1^2 + 5^2 + 9^2]

但是为什么我们要写sim/norms/norms.T来计算余弦相似度呢?任何帮助都将不胜感激。


1
我之前在http://codereview.stackexchange.com/questions/159231/cosine-similarity-optimization上发布了这个问题,并得到了一条评论,说那不是正确的地方。我希望这里是这样的问题的正确场所。 - Manish Kumar
详情请参考:源代码已从http://blog.ethanrosenthal.com/2015/11/02/intro-to-collaborative-filtering/获取。 - Manish Kumar
1个回答

4

浏览代码,我们可以得到:

first

这意味着,在sim矩阵的对角线上,我们有每列相乘的结果。

如果您想使用一个简单的矩阵来尝试,请随意使用:

second

您可以轻松检查这个格拉姆矩阵(这就是这个矩阵乘积的名称)具有此属性。

现在,代码定义了norms,它只是一个获取我们gram matrix对角线并在其每个元素上应用sqrt的数组。

这将给我们一个包含每列的规范值的数组:

third

因此,基本上norms向量包含result矩阵的每列的规范值。

一旦我们拥有所有这些数据,我们就可以评估这些用户之间的余弦相似度,因此我们知道余弦相似度的计算方式如下:

forth

请注意: fifth

所以我们得到的相似度为:

six

因此,我们只需将项替换为我们的代码变量,即可获得:

seven

这就解释了为什么你需要这行代码:

return sim / norms / norms.T

编辑: 看起来我的表述不太清楚,我在这个回答中每次提到矩阵乘法时都是指两个矩阵的点积

这意味着当写成A*B时,我们实际上要展开并解决A.T * B。


你的意思是 A * B = transpose(A) * A 吗? - Moses Koledoye
我们正在谈论“点积”。 - rakwaht
如果您明确指定,那么会更好。 - Moses Koledoye
你在哪里读到norms = A.T?我的意思是:“代码定义了范数,它实际上是一个数组,取我们的Gram矩阵的对角线并在每个元素上应用sqrt。” - rakwaht
规范向量应该包含目标矩阵A的每一行的归一化值。由于我们的规范数组包含A的每一列的一个归一化值,因此我们可以说这正好是||A.T||(请注意,如果我们转置A,现在规范包含A.T的所有归一化值的行)。 - rakwaht
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接