Kas*_*sun 3 java lucene similarity
我\xe2\x80\x99m 通过在索引时指定 TermVector 来使用 Lucene 索引文档集合。\n然后,我通过读取索引并计算每个文档的 TF-IDF 得分向量来检索术语及其频率。然后,使用 TF-IDF 向量,使用维基百科的余弦相似度方程计算文档之间的成对余弦相似度。
\n\n这是我的问题:假设我在这个集合中有两个相同的文档 \xe2\x80\x9cA\xe2\x80\x9d 和 \xe2\x80\x9cB\xe2\x80\x9d (A 和 B 有超过 200 个句子)。如果我计算 A 和 B 之间的成对余弦相似度,它会给出余弦值=1,这是完全可以的。但是,如果我从 Doc \xe2\x80\x9cB\xe2\x80\x9d 中删除单个句子,它会给出这两个文档之间的余弦相似度值约为 0.85。这些文档几乎相似,但余弦值却不同。我知道问题出在 I\xe2\x80\x99m 使用的方程上。
\n\n有没有更好的方法/方程可以用来计算文档之间的余弦相似度?
\n\n已编辑
\n\n这就是我计算余弦相似度的方法,doc1[]并且doc2[]是相应文档的 TF-IDF 向量。向量仅包含scores但不包含words
private double cosineSimBetweenTwoDocs(float doc1[], float doc2[]) {\n double temp;\n int doc1Len = doc1.length;\n int doc2Len = doc2.length;\n float numerator = 0;\n float temSumDoc1 = 0;\n float temSumDoc2 = 0;\n double equlideanNormOfDoc1 = 0;\n double equlideanNormOfDoc2 = 0;\n if (doc1Len > doc2Len) {\n for (int i = 0; i < doc2Len; i++) {\n numerator += doc1[i] * doc2[i];\n temSumDoc1 += doc1[i] * doc1[i];\n temSumDoc2 += doc2[i] * doc2[i];\n }\n equlideanNormOfDoc1=Math.sqrt(temSumDoc1);\n equlideanNormOfDoc2=Math.sqrt(temSumDoc2);\n } else {\n for (int i = 0; i < doc1Len; i++) {\n numerator += doc1[i] * doc2[i];\n temSumDoc1 += doc1[i] * doc1[i];\n temSumDoc2 += doc2[i] * doc2[i];\n }\n equlideanNormOfDoc1=Math.sqrt(temSumDoc1);\n equlideanNormOfDoc2=Math.sqrt(temSumDoc2);\n }\n\n temp = numerator / (equlideanNormOfDoc1 * equlideanNormOfDoc2);\n return temp;\n} \nRun Code Online (Sandbox Code Playgroud)\n
正如我在评论中告诉你的,我认为你在某个地方犯了错误。这些向量实际上不仅包含<word,frequency>对words。因此,删除句子时,只是对应单词的频率减1(后面的单词不移位)。考虑以下示例:
文件一:
A B C A A B C. D D E A B. D A B C B A.
Run Code Online (Sandbox Code Playgroud)
文件b:
A B C A A B C. D A B C B A.
Run Code Online (Sandbox Code Playgroud)
向量a:
A:6, B:5, C:3, D:3, E:1
Run Code Online (Sandbox Code Playgroud)
向量b:
A:5, B:4, C:3, D:1, E:0
Run Code Online (Sandbox Code Playgroud)
这导致以下相似性度量:
(6*5+5*4+3*3+3*1+1*0)/(Sqrt(6^2+5^2+3^2+3^2+1^2) Sqrt(5^2+4^2+3^2+1^2+0^2))=
62/(8.94427*7.14143)=
0.970648
Run Code Online (Sandbox Code Playgroud)
编辑 我认为你的源代码不能正常工作。考虑下面的代码,它与上面的示例配合得很好:
import java.util.HashMap;
import java.util.Map;
public class DocumentVector {
Map<String, Integer> wordMap = new HashMap<String, Integer>();
public void incCount(String word) {
Integer oldCount = wordMap.get(word);
wordMap.put(word, oldCount == null ? 1 : oldCount + 1);
}
double getCosineSimilarityWith(DocumentVector otherVector) {
double innerProduct = 0;
for(String w: this.wordMap.keySet()) {
innerProduct += this.getCount(w) * otherVector.getCount(w);
}
return innerProduct / (this.getNorm() * otherVector.getNorm());
}
double getNorm() {
double sum = 0;
for (Integer count : wordMap.values()) {
sum += count * count;
}
return Math.sqrt(sum);
}
int getCount(String word) {
return wordMap.containsKey(word) ? wordMap.get(word) : 0;
}
public static void main(String[] args) {
String doc1 = "A B C A A B C. D D E A B. D A B C B A.";
String doc2 = "A B C A A B C. D A B C B A.";
DocumentVector v1 = new DocumentVector();
for(String w:doc1.split("[^a-zA-Z]+")) {
v1.incCount(w);
}
DocumentVector v2 = new DocumentVector();
for(String w:doc2.split("[^a-zA-Z]+")) {
v2.incCount(w);
}
System.out.println("Similarity = " + v1.getCosineSimilarityWith(v2));
}
}
Run Code Online (Sandbox Code Playgroud)