Java余弦相似度问题

3
我开发了一些Java程序来基于TF * IDF计算余弦相似度。它运行得非常好。但是有一个问题.... :(
例如: 如果我有以下两个矩阵,并且我想计算余弦相似度,由于行的长度不同,它无法工作。
doc 1
1 2 3
4 5 6

doc 2
1 2 3 4 5 6
7 8 5 2 4 9

如果行和列的长度相同,那么我的程序将非常好地工作,但如果它们的长度不同,则不会。有什么提示吗?
2个回答

3
简单的Java余弦相似性。
 static double cosine_similarity(Map<String, Double> v1, Map<String, Double> v2) {
            Set<String> both = Sets.newHashSet(v1.keySet());
            both.removeAll(v2.keySet());
            double sclar = 0, norm1 = 0, norm2 = 0;
            for (String k : both) sclar += v1.get(k) * v2.get(k);
            for (String k : v1.keySet()) norm1 += v1.get(k) * v1.get(k);
            for (String k : v2.keySet()) norm2 += v2.get(k) * v2.get(k);
            return sclar / Math.sqrt(norm1 * norm2);
    }

3
我不确定你的实现方式,但是两个向量的余弦距离等于这些向量的归一化点积。
两个矩阵的点积可以表示为a . b = aTb。因此,如果矩阵长度不同,则无法通过点积来识别余弦值。
现在,在标准的TF*IDF方法中,矩阵中的术语应该按term, document索引,因此在文档中未出现的任何术语都应该在您的矩阵中出现为零。
现在,您设置的方式似乎表明有两个不同的矩阵用于您的两个文档。我不确定这是否是您的意图,但它似乎是不正确的。
另一方面,如果其中一个矩阵应该是您的查询,则它应该是一个向量而不是矩阵,以便转置产生正确的结果。
以下是TF*IDF的完整解释:

在经典的TF-IDF中,您需要构建一个术语-文档矩阵a。矩阵a中的每个值都被描述为ai,j,其中i是术语,j是文档。该值是局部、全局和归一化权重的组合(如果您对文档进行了归一化,则归一化权重应为1)。因此,ai,j=fi,j*D/di,其中fi,j是单词i在文档j中的频率,D是文档大小,di是包含术语i的文档数量。

您的查询是一个术语向量,指定为b。对于查询q中的每个术语bi,q,它都指代查询q的术语i。bi,q=fi,q,其中fi,q是查询q中术语i的频率。在这种情况下,每个查询都是一个向量,多个查询形成一个矩阵。

我们可以计算每个向量的单位向量,这样当我们取点积时,它将产生正确的余弦值。为了实现单位向量,我们将矩阵 a 和查询 b 都除以它们的Frobenius norm
最后,我们可以通过对给定查询的向量b进行转置来执行余弦距离。因此,每次计算只有一个查询(或向量)。这被表示为 bTa。最终结果是一个包含每个项得分的向量,其中较高的得分表示更高的文档排名。

谢谢你的回答。是的,我的第一个矩阵是查询。查询和向量之间有什么区别?它们不是几乎一样吗?我正在使用一个文档作为查询,第二个文档作为目标。这就是我分别为目标计算tfidf和查询的原因。我不能使用转置,因为我不知道确切的列和行数。这只是一个问题中的示例 :)。你能否请再解释一下如何解决我的问题?我应该为查询和目标创建一个tfidf吗?如果是的话,我如何计算余弦? - user238384
@agazerboy 这样足够了吗?还需要更详细的解释吗? - tzenes

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