调整余弦相似度不正常工作

本文关键字:不正常 工作 相似 余弦 调整 | 更新日期: 2023-09-27 18:18:15

我正在开发一个基于项目的协同过滤器,使用餐厅之间调整后的余弦相似度来生成推荐。我把所有的东西都设置好了,它运行得很好,但是当我试图模拟可能的测试场景时,我得到了一些有趣的结果。

我将从我的测试数据开始。我有2家餐厅,我想计算它们之间的相似度,有3个用户对这2家餐厅的评价都是一样的。我将使用下面的矩阵来解释它:

               User 1 | User 2 | User 3
Restaurant 1 |   1    |   2    |   1
Restaurant 2 |   1    |   2    |   1

我正在尝试使用以下函数计算相似性:
在我的代码中,餐厅被称为Subject

public double ComputeSimilarity(Guid subject1, Guid subject2, IEnumerable<Review> allReviews)
{
    //This will create an IEnumerable of reviews from the same user on the 2 restaurants.
    var matches = (from R1 in allReviews.Where(x => x.SubjectId == subject1)
                   from R2 in allReviews.Where(x => x.SubjectId == subject2)
                   where R1.UserId == R2.UserId
                   select new { R1, R2 });            
    double num = 0.0f;
    double dem1 = 0.0f;
    double dem2 = 0.0f;
    //For the similarity between subjects, we use an adjusted cosine similarity.
    //More information on this can be found here: http://www10.org/cdrom/papers/519/node14.html
    foreach (var item in matches)
    {
        //First get the average of all reviews the user has given. This is used in the adjusted cosine similarity, read the article from the link for further explanation
        double avg = allReviews.Where(x => x.UserId == item.R1.UserId)
                               .Average(x => x.rating);
        num += ((item.R1.rating - avg) * (item.R2.rating - avg));
        dem1 += Math.Pow((item.R1.rating - avg), 2);
        dem2 += Math.Pow((item.R2.rating - avg), 2);
    }
    return (num / (Math.Sqrt(dem1) * Math.Sqrt(dem2)));
}

我的评论是这样的:

public class Review
{
    public Guid Id { get; set; }
    public int rating { get; set; } //This can be an integer between 1-5
    public Guid SubjectId { get; set; } //This is the guid of the subject the review has been left on
    public Guid UserId { get; set; } //This is the guid of the user who left the review
}

在所有其他情况下,该函数将计算出受试者之间的正确相似度。但是当我使用上面的测试数据(我期望完美的相似性)时,它会产生NaN。

这是一个错误在我的代码或这是一个错误在调整余弦相似度?如果它的结果是NaN,捕获它并插入1以获得相似性是好的吗?

编辑:我也尝试过其他矩阵,我得到了更有趣的结果。

               User 1 | User 2 | User 3 | User 4 | User 5
Restaurant 1 |   1    |   2    |   1    |   1    |   2
Restaurant 2 |   1    |   2    |   1    |   1    |   2

这仍然导致NaN。

               User 1 | User 2 | User 3 | User 4 | User 5
Restaurant 1 |   2    |   2    |   1    |   1    |   2
Restaurant 2 |   1    |   2    |   1    |   1    |   2

这导致-1的相似性

调整余弦相似度不正常工作

看来你的算法是正确实现的。问题是,对于完全合理的集合,这个公式在某些点上确实是没有定义的。您可以将这种情况视为"此度量(调整余弦相似度)与提供的集合无关",因此分配任意值(0,1,-1)是不正确的。相反,在这种情况下使用不同的度量。例如,简单的(未经调整的)余弦相似度将给出"1"的结果,这是你可能期望的。