1. 使用simhash計算文本相似度
2. 使用余弦相似度計算文本相似度
3. 使用編輯距離計算文本相似度
4. jaccard系數計算文本相似度
4. jaccard系數計算文本相似度
4.1 jaccard系數
jaccard系數反映了兩個向量(元素取值為0或1)間的關系。即對於
和
,定義:
=
中元素值為0且
中元素值為0的個數
=
中元素值為1且
中元素值為0的個數
=
中元素值為0且
中元素值為1的個數
=
中元素值為1且
中元素值為1的個數
則 jaccard系數可以表示為:
當向量中為0的元素遠大於為1的元素的個數時, 需要從計算中移除,而只關注均為1的元素的個數。因為當 較大時,整個計算結果將區域穩定,無明顯特征了。所以以上公式變為:
另一種用集合表示的方法:
4.2 jaccard系數相似度
jaccard系數值越大,相似度越高,另一種說法是用jaccard距離表示相似度即: ,本質一樣,但jaccard距離越大相似度越小。
一般的 jaccard系數只適用於計算元素取值為0或1的集合,但是要注意的是這里取值為0或1並不是值集合中的值為0或1,而僅僅是集合中元素的取值為0或1,而計算出的jaccard系數是和元素本身相關的。
4.2.1 jaccard系數衡量維度相似性
jaccard系數很適合用來分析多個維度間的相似性,也多被用於推薦系統中用來給用戶推薦相似的產品或業務。
舉個例子,要計算某網站的兩個用戶的相似性,可以從性別、地區、年齡、瀏覽時間等等維度進行分析,我們把這些維度再進行細化:
男性、女性、小於18歲、18歲-40歲、40歲以上、瀏覽時間為早上、瀏覽時間為中午、瀏覽時間為下午
將以上維度作為一個集合,對兩個用戶
和
,將符合以上維度的指標值置為1,其他置為0。
假設用戶
=[男性=1, 女性=0, 小於18歲=0, 18歲-40歲=1, 40歲以上=0, 瀏覽時間為早上=0, 瀏覽時間為中午=0, 瀏覽時間為下午=1]
假設用戶
=[男性=1, 女性=0, 小於18歲=1, 18歲-40歲=0, 40歲以上=0, 瀏覽時間為早上=0, 瀏覽時間為中午=0, 瀏覽時間為下午=1]
即他們只有年齡不同,則根據計算公式,得到的jaccard系數值為:
即他們的相似度為0.5
用matlab驗證下:
4.2.1 jaccard系數衡量文本相似性
雖然jaccard主要是在維度分析這樣的稀疏向量中作用比較大,但是在文本相似度計算時也可用jaccard。
仍然用之前的文本作為輸入樣本:
樣本1:今天天氣真好
樣本2:今天天氣不錯
首先要做的還是分詞:
A = [今天,天氣,真好]
B = [今天,天氣,不錯]
轉化為01向量,用matlab驗證下:
4.3 jaccard系數計算實現(java)
public static double jaccard(String s1, String s2) {
List<String> words1 = splitWords(s1);
List<String> words2 = splitWords(s2);
List<String> temp = new ArrayList<>();
temp.addAll(words1);
temp.addAll(words2);
List<String> union = temp.stream().distinct().collect(Collectors.toList());
List<String> intersect = new ArrayList<>();
List<String> a = words1.stream().
map(x -> words2.contains(x) ? x : null).
collect(Collectors.toList());
List<String> b = words2.stream().
map(x -> words1.contains(x) ? x : null).
collect(Collectors.toList());
intersect.addAll(a);
intersect.addAll(b);
intersect = intersect.stream().distinct().collect(Collectors.toList());
intersect.removeAll(Collections.singleton(null));
return 1.0 * intersect.size() / union.size();
}
4.4 總結
以上只是簡單的從字符出現或者沒有出現的角度進行相似度計算,而沒有考慮其他因素。實際上,還可以結合詞義進行近義詞替換,來進一步達到語義層面的相似度計算,這樣結果會更為准確。
下面時jaccard的耗時: