余弦相似度
2013-01-09 14:46 ggzwtj 阅读(140) 评论(0) 收藏 举报首先,先来想一下怎样来定义两个文本之间的“距离”?当然,要先转换成数学的模型,比如有四段文本:
AAAA
AABBBBBB
AAAAABBBBBBBBBBB
AAAAAAAAAAABB
如果分别对‘A’、‘B’统计可以将每段文字都映射到平面空间中:
那么能不能像计算两点之间距离那样来反应他们之间的差距?
这样判断的结果是“AAAA”与“AAAAABBBBBBBBBBB”的相似度与“AABBBBBB”和“AAAAABBBBBBBBBBB”之间的相似度,显然这是不准确的,“AAAA”里面连‘B’都没有怎么能说是相似呢?
那是什么导致了不准确?
如果一个文本是400字的,把它拿过来DOUBLE一下变成了800字,那么这两个文本之间的距离也是非常大的。显然,我们在考虑文本相似度的时候需要有一个定的量,如果把文本的总的字数定下来,那么这种情况就可以缓解了。那么直观上可以看到字数固定之后,各个向量之间的夹角可以大致反映两个文本的相似程度(也就是余弦相似度):
具体的实现的代码如下:
public static double cosineSimilar(String str1, String str2) {
if (StringUtils.isBlank(str1) || StringUtils.isBlank(str2)) {
return 0.0;
}
Map<Character, Integer> map = new HashMap<Character, Integer>();
int[] m = new int[500];
int[] n = new int[500];
int sumIndex = 0;
Integer index = null;
for (int i = 0; i < str1.length(); i++) {
char ch = str1.charAt(i);
index = map.get(ch);
if (index == null) {
map.put(ch, sumIndex++);
index = sumIndex;
}
if (index < 500)
m[index]++;
}
for (int i = 0; i < str2.length(); i++) {
char ch = str2.charAt(i);
index = map.get(ch);
if (index == null) {
map.put(ch, sumIndex++);
index = sumIndex;
}
if (index < 500)
n[index]++;
}
double mn = 0.0, mm = 0.0, nn = 0.0;
for (int i = 0; i < sumIndex; i++) {
mn += m[i] * n[i];
mm += m[i] * m[i];
nn += n[i] * n[i];
}
mm /= str1.length() * str1.length();
nn /= str2.length() * str2.length();
mn /= str1.length() * str2.length();
return Math.sqrt(mn / ((mm + nn) * 0.5));
}
浙公网安备 33010602011771号