1. 程式人生 > >計算字串相似度的一些方法

計算字串相似度的一些方法

產品出了一個奇怪的需求,想通過字串相似度取匹配城市= =(當然,最後證實通過字串相似度取判斷兩個字串是不是一個城市是不對的!!!)

這裡就記錄一下我計算字串(英文字串)相似度的方法吧~

參考文件:

Levenshtein

  • Levenshtein.hamming(str1, str2)

    計算漢明距離。要求str1和str2必須長度一致。是描述兩個等長字串之間對應位置上不同字元的個數。

    用法:

    >>> import Levenshtein     
    >>> Levenshtein.hamming('abc', 'cba')
    2
    >>> Levenshtein.
    hamming('abc', 'def') 3
  • 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`
後面兩個引數就是需要比較的兩個物件了

餘弦定理

通過閱讀上面的文章,我們可以簡單總結計算相似度的幾個步驟:

  1. 列出所有出現的字母,並分別統計兩個字串出現這些字母的次數。這裡我是這樣寫的,利用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)])
    

    這樣寫的原因是,在比較詞頻的時候,要保證每個字母的順序是一樣的~

  2. 利用餘弦公式計算相似度

    方法:

    >>> 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:本文說的計算的字串,全是英文字串~~