java余弦相似度问题

时间:2010-02-23 03:49:57

标签: java math

我开发了一些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 个答案:

答案 0 :(得分:3)

我不确定你的实现,但两个向量的cosine distance等于这些向量的标准化点积。

两个矩阵的点积可以表示为a。 b = a T b。因此,如果矩阵具有不同的长度,则无法使用点积来识别余弦。

现在,在标准TF * IDF方法中,矩阵中的术语应由term, document索引,因此,未出现在文档中的任何术语应在矩阵中显示为零。

现在你设置的方式似乎表明你的两个文件有两个不同的矩阵。我不确定这是否是你的意图,但似乎不正确。

另一方面,如果你的一个矩阵应该是你的查询,那么它应该是一个向量而不是一个矩阵,这样转置会产生正确的结果。

TF * IDF的完整解释如下:

好的,在经典的TF * IDF中,您构建了一个术语 - 文档矩阵a。矩阵a中的每个值都被表征为 i,j ,其中i是术语,j是文档。此值是本地,全局和标准化权重的组合(尽管如果您规范化文档,则标准化权重应为1)。因此, i,j = f i,j * D / d i ,其中f i,j 是文档i中单词j的频率,D是文档大小,d i 是条款为i的文档数它们。

您的查询是指定为b的字词向量。对于每个术语b i,查询中的q 指的是查询i的术语q。 b i,q = f i,q 其中f i,q 是查询{{1}中术语i的频率}}。在这种情况下,每个查询都是一个向量,多个查询形成一个矩阵。

然后我们可以计算每个的单位向量,这样当我们采用点积时它将产生正确的余弦。为了实现单位向量,我们将矩阵q和查询a除以Frobenius norm

最后,我们可以通过对给定查询进行向量b的转置来执行余弦距离。因此,每次计算一个查询(或向量)。这表示为b T a。最终结果是具有每个术语得分的向量,其中较高得分表示较高的文档等级。

答案 1 :(得分: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);
    }