我开发了一些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
如果行和列的长度相同,那么我的程序工作得非常好,但如果行和列的长度不相同则不行。
任何提示???
答案 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);
}