gpt4 book ai didi

java - 使用 Lucene 计算文档相似度的更好方法

转载 作者:行者123 更新时间:2023-11-30 07:25:53 25 4
gpt4 key购买 nike

我通过在索引时指定 TermVector 使用 Lucene 索引文档集合。然后我通过读取索引并计算每个文档的 TF-IDF 分数 vector 来检索术语及其频率。然后,使用 TF-IDF vector ,我使用 Wikipedia's cosine similarity equation 计算文档之间的成对余弦相似度。 .

这是我的问题:假设我在这个集合中有两个相同的文档“A”和“B”(A 和 B 有 200 多个句子)。如果我计算 A 和 B 之间的成对余弦相似度,它会给出余弦值 = 1,这完全可以。但是,如果我从文档“B”中删除一个句子,这两个文档之间的余弦相似度值约为 0.85。这些文档几乎相似,但余弦值不同。我知道问题出在我使用的方程式上。

是否有更好的方法/方程式可用于计算文档之间的余弦相似度?

已编辑

这是我计算余弦相似度的方法,doc1[]doc2[] 是相应文档的 TF-IDF vector 。该 vector 仅包含 scores 但不包含 words

private double cosineSimBetweenTwoDocs(float doc1[], float doc2[]) {
double temp;
int doc1Len = doc1.length;
int doc2Len = doc2.length;
float numerator = 0;
float temSumDoc1 = 0;
float temSumDoc2 = 0;
double equlideanNormOfDoc1 = 0;
double equlideanNormOfDoc2 = 0;
if (doc1Len > doc2Len) {
for (int i = 0; i < doc2Len; i++) {
numerator += doc1[i] * doc2[i];
temSumDoc1 += doc1[i] * doc1[i];
temSumDoc2 += doc2[i] * doc2[i];
}
equlideanNormOfDoc1=Math.sqrt(temSumDoc1);
equlideanNormOfDoc2=Math.sqrt(temSumDoc2);
} else {
for (int i = 0; i < doc1Len; i++) {
numerator += doc1[i] * doc2[i];
temSumDoc1 += doc1[i] * doc1[i];
temSumDoc2 += doc2[i] * doc2[i];
}
equlideanNormOfDoc1=Math.sqrt(temSumDoc1);
equlideanNormOfDoc2=Math.sqrt(temSumDoc2);
}

temp = numerator / (equlideanNormOfDoc1 * equlideanNormOfDoc2);
return temp;
}

最佳答案

正如我在评论中告诉您的那样,我认为您在某处犯了错误。这些 vector 实际上包含 <word,frequency>对,不是 words仅有的。因此,当你删除句子时,只是将相应词的频率减1(后面的词不移位)。考虑以下示例:

文件一:

A B C A A B C. D D E A B. D A B C B A.

文件b:

A B C A A B C. D A B C B A.

vector a:

A:6, B:5, C:3, D:3, E:1

vector b:

A:5, B:4, C:3, D:1, E:0

这导致以下相似性度量:

(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

编辑我认为您的源代码也无法正常工作。考虑以下适用于上述示例的代码:

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

}

关于java - 使用 Lucene 计算文档相似度的更好方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10649898/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com