簡體   English   中英

如何測量句子之間的字符串相似度?

[英]How can I measure string similarity between sentences?

我有以下任務。

給出的字符串列表如下:

        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了一下,發現了這個: 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%?

“史蒂夫·喬布斯在他上蘋果時創造了iPod”,只是“史蒂夫”匹配只有10%,盡管在第一句話中使用的是“史蒂夫”一詞嗎?

如何獲得更好的語義結果? Levenshtein是錯誤的算法嗎? 根據我的理解,Levenshtein計算了如何將句子1改為句子2的步驟數。因此,即使存在語義相似性,字符串的長度似乎也會對結果產生重大影響。

有什么建議?

你可能應該使用兩個句子中的單詞作為高度相似性。 一個簡單的方法是使用每個句子作為一個單詞並使用tf-idf

您可以使用的是規范化的最長公共子序列(LCS)相似度:您計算最長公共子序列的長度,然后除以最小字符串的長度。

順便說一句,最長的公共子序列不應該與最長的公共子串混淆:對於兩個字符串“這是一個長字符串”和“這是另一個字符串,真的......”

最長的常見子序列是“這是一個字符串”
最長的共同子串是“這是一個”

相對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

SimMetrics擁有Smith Waterman Gotoh算法的java代碼 ,非常適合比較字符串句子。 我發現Smith Waterman Gotoh是比較較大字符串(例如句子和文章標題)優秀算法

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM