我有以下任务。
给出一个像这样的字符串列表:
var strings = [
'Steve jobs created the iPod when he was at Apple',
'I really like the new Macbook by Apple',
'Jony Ive was concerned being fired by Steve Jobs after his return to Apple',
'The new Macbook has just one USB-C type connector',
'I like bananas',
'The brezels I can buy in my local store are much better than the ones in the supermarket',
'the',
'foo',
'Steve'
];
我现在想要将每个字符串相互比较,并且对于每个比较,我想知道它们在0-1(或0%-100%)的范围内彼此之间的相似程度。
所以,我用Google搜索了一下,发现了这个:Similarity String Comparison in Java
所以,我按照那里的指令,将方法similarity(String s1, String s2)
移植到JavaScript:
function similarity(s1, s2) {
var longer = s1;
var shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
var longerLength = longer.length;
if (longerLength == 0) {
return 1.0;
}
return (longerLength - longer.LevenshteinDistance(shorter)) / longerLength;
}
作为比较算法,我使用了Levenshtein:
String.prototype.LevenshteinDistance = function (s2) {
var array = new Array(this.length + 1);
for (var i = 0; i < this.length + 1; i++)
array[i] = new Array(s2.length + 1);
for (var i = 0; i < this.length + 1; i++)
array[i][0] = i;
for (var j = 0; j < s2.length + 1; j++)
array[0][j] = j;
for (var i = 1; i < this.length + 1; i++) {
for (var j = 1; j < s2.length + 1; j++) {
if (this[i - 1] == s2[j - 1]) array[i][j] = array[i - 1][j - 1];
else {
array[i][j] = Math.min(array[i][j - 1] + 1, array[i - 1][j] + 1);
array[i][j] = Math.min(array[i][j], array[i - 1][j - 1] + 1);
}
}
}
return array[this.length][s2.length];
};
所以,作为测试,我运行了一个完整的循环,将每个字符串相互比较并打印结果如下:
for (var i in strings){
var s = strings[i];
print('Checking string: "' + s + '"');
for (var j in strings){
print('-----');
var s2 = strings[j];
print('vs "' + s2 + '"');
var sim = similarity(s, s2);
print('Similarity: ' + Math.round(sim*100) + '%');
}
print('<br>////// NEXT /////////////////////////////////////////////////<br>');
}
好的,现在结果是:https://jsfiddle.net/wxksfa4w/
现在,看看结果我得到了一些很好的匹配,但也有一些完全不相互关联,例如:
“史蒂夫·乔布斯在他上苹果时创造了iPod”和“我喜欢香蕉”的比赛为13%?
“当他在Apple时,史蒂夫·乔布斯创造了iPod”,只有“史蒂夫”匹配只有10%,尽管在第一句中使用了与“史蒂夫”完全相同的词语吗?如何获得更好的语义结果? Levenshtein是错误的算法吗?根据我的理解,Levenshtein计算了如何将句子1改为句子2的步骤数。因此,即使存在语义相似性,字符串的长度似乎也会对结果产生重大影响。
有什么建议吗?
答案 0 :(得分:1)
你可能应该使用两个句子中的单词作为高度相似性。一个简单的方法是使用每个句子作为一个单词并使用tf-idf
答案 1 :(得分:0)
您可以使用的是归一化最长公共子序列(LCS)相似度:您计算最长公共子序列的长度,然后除以最小字符串的长度。
顺便说一下,最长的公共子序列不应该与最长的公共子串混淆:对于两个字符串&#34;这是一个长字符串&#34;和&#34;这是另一个字符串,真的......&#34;
最长的公共子序列是&#34;这是一个字符串&#34;
最长的公共子串是&#34;这是&#34;
相对LCS相似度为16/21 = 0.76
您可以在此处找到LCS相似性的Java实现:https://github.com/tdebatty/java-string-similarity
在wikibooks上可以使用Javascript实现:https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_subsequence#JavaScript
答案 2 :(得分:0)
SimMetrics对java code算法Smith Waterman Gotoh superior algorithm for comparing larger strings such as sentences and article titles,这对于比较字符串句子非常有用。我发现Smith Waterman Gotoh是http://localhost:8080/manager/html/list。