計算字串相似度的一些方法
產品出了一個奇怪的需求,想通過字串相似度取匹配城市= =(當然,最後證實通過字串相似度取判斷兩個字串是不是一個城市是不對的!!!)
這裡就記錄一下我計算字串(英文字串)相似度的方法吧~
參考文件:
Levenshtein
-
Levenshtein.hamming(str1, str2)
計算漢明距離。要求str1和str2必須長度一致。是描述兩個等長字串之間對應位置上不同字元的個數。
用法:
>>> import Levenshtein >>> Levenshtein.hamming('abc', 'cba') 2 >>> Levenshtein.
-
Levenshtein.distance(str1, str2)
計算編輯距離(也成Levenshtein距離)。是描述由一個字串轉化成另一個字串最少的操作次數,在其中的操作包括插入、刪除、替換。
用法:
>>> Levenshtein.distance('abc', 'ab') 1 >>> Levenshtein.distance('cxy', 'ab') 3
-
Levenshtein.ratio(str1, str2)
計算萊文斯坦比。計算公式 r = (sum - ldist) / sum, 其中sum是指str1 和 str2 字串的長度總和,ldist是類編輯距離
注意:這裡的類編輯距離不是
Levenshtein.distance(str1, str2)
所說的編輯距離,Levenshtein.distance(str1, str2)
中三種操作中每個操作+1,而在此處,刪除、插入依然+1,但是替換+2 這樣設計的目的:ratio(‘a’, ‘c’),sum=2,按2中計算為(2-1)/2 = 0.5,’a’,'c’沒有重合,顯然不合算,但是替換操作+2,就可以解決這個問題。用法:
>>> Levenshtein.ratio('a,cdsf', 'abcd') 0.6
difflib
我主要用的是SequenceMatcher
SequenceMatcher
.
SequenceMatcher
是可以對兩個可序列化的物件進行比較的類
官網上的用法是:
>>> s = SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
>>> print(round(s.ratio(), 3))
0.866
第一個引數為一個函式,主要用來去掉自己不想算在內的元素;如果沒有,可以寫`None`
後面兩個引數就是需要比較的兩個物件了
餘弦定理
通過閱讀上面的文章,我們可以簡單總結計算相似度的幾個步驟:
-
列出所有出現的字母,並分別統計兩個字串出現這些字母的次數。這裡我是這樣寫的,利用
from collections import Counter, OrderedDict
方法:
>>> from collections import Counter, OrderedDict >>> from copy import deepcopy >>> a = 'abc' >>> b = 'bcde' >>> item = set(a) | set(b) >>> item {'b', 'c', 'e', 'd', 'a'} >>> model = OrderedDict().fromkeys(item) >>> model OrderedDict([('b', None), ('c', None), ('e', None), ('d', None), ('a', None)]) >>> model1 = deepcopy(model) >>> model2 = deepcopy(model) >>> model1.update(Counter(a)) >>> model1 OrderedDict([('b', 1), ('c', 1), ('e', None), ('d', None), ('a', 1)]) >>> model2.update(Counter(b)) >>> model2 OrderedDict([('b', 1), ('c', 1), ('e', 1), ('d', 1), ('a', None)])
這樣寫的原因是,在比較詞頻的時候,要保證每個字母的順序是一樣的~
-
利用餘弦公式計算相似度
方法:
>>> import math >>> sum = 0 #分子 >>> q1 = 0 #分母 >>> q2 = 0 #分母 >>> for i in item: a = model1[i] if type(model1[i]) != type(None) else 0 b = model2[i] if type(model2[i]) != type(None) else 0 sum += a * b q1 += pow(a, 2) q2 += pow(b, 2) >>> sum 2 >>> q1 3 >>> q2 4 >>> result = float(sum) / (math.sqrt(q1) * math.sqrt(q2)) >>> result 0.5773502691896258
這樣就算出相似度啦~
ps:本文說的計算的字串,全是英文字串~~