2010-02-23 93 views
3

我开发了一些基于TF * IDF的java程序来计算余弦相似度。它工作得很好。但有一个问题.... :(java余弦相似度问题

例如: 如果我有以下两个矩阵,我要计算余弦相似度它不起作用为行长度不

doc 1 
1 2 3 
4 5 6 

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

相同如果行和colums的长度是相同的,然后我的程序工作得很好,但它没有,如果行和列不在相同的长度。

任何提示???

回答

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 ,其中f I,J是字i在DOC j频率,D是文档尺寸,和d 是其中包含术语i的文档的数量。

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

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

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

+0

谢谢您的回答。是的,我的第一个矩阵是查询。什么是差异。查询和向量之间?它们不是几乎一样吗?我使用一个文档作为查询,第二个作为目标。这就是我分别为目标计算tf * idf和为查询计算tf * idf的原因。我不能使用transponse因为我不知道确切的列和行数。这只是一个例子:)问题。你能解释一下我该怎么解决我的问题?我应该为查询和目标创建一个tf * idf吗?如果是,那么我将如何计算余弦? – user238384 2010-02-23 04:12:18

+0

我会尝试添加到我的答案 – tzenes 2010-02-23 04:49:56

+0

@agazerboy是否足够或您需要更多的解释? – tzenes 2010-02-27 21:31:41

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); 
    }