NLP句子相似性方法總結及實現

目錄

1、基於Word2Vec的餘弦相似度

2、TextRank算法中的句子相似性

3、萊文斯坦距離(編輯距離)

4、萊文斯坦比

5、漢明距離

6、Jaro距離(Jaro Distance)

7、Jaro-Winkler距離(Jaro-Winkler Distance)


1、基於Word2Vec的餘弦相似度

首先對句子分詞,使用Gensim的Word2Vec訓練詞向量,獲取每個詞對應的詞向量,然後將所有的詞向量相加求平均,得到句子向量,最後計算兩個句子向量的餘弦值(餘弦相似度)。

餘弦相似度:用向量空間中的兩個向量夾角的餘弦值作爲衡量兩個個體間差異大小的度量,值越接近1,就說明夾角角度越接近0°,也就是兩個向量越相似。

公式:

代碼實現:

#對每個句子的所有詞向量取均值,來生成一個句子的vector
#sentence是輸入的句子,size是詞向量維度,w2v_model是訓練好的詞向量模型
def build_sentence_vector(sentence,size,w2v_model):
    vec=np.zeros(size).reshape((1,size))
    count=0
    for word in sentence:
        try:
            vec+=w2v_model[word].reshape((1,size))
            count+=1
        except KeyError:
            continue
    if count!=0:
        vec/=count
    return vec

#計算兩個句向量的餘弦相似性值
def cosine_similarity(vec1, vec2):
    a= np.array(vec1)
    b= np.array(vec2)
    cos1 = np.sum(a * b)
    cos21 = np.sqrt(sum(a ** 2))
    cos22 = np.sqrt(sum(b ** 2))
    cosine_value = cos1 / float(cos21 * cos22)
    return cosine_value

#輸入兩個句子,計算兩個句子的餘弦相似性
def compute_cosine_similarity(sents_1, sents_2):
    size=300
    w2v_model=Word2Vec.load('w2v_model.pkl')
    vec1=build_sentence_vector(sents_1,size,w2v_model)
    vec2=build_sentence_vector(sents_2,size,w2v_model)
    similarity = cosine_similarity(vec1, vec2)
    return similarity

2、TextRank算法中的句子相似性

句子相似性公式:

公式中,Si,Sj分別表示兩個句子,Wk表示句子中的詞,那麼分子部分的意思是同時出現在兩個句子中的相同詞的個數,分母是對句子中詞的個數求對數之和。分母這樣設計可以遏制較長的句子在相似度計算上的優勢。

代碼實現:

def two_sentences_similarity(sents_1, sents_2):
    counter = 0
    for sent in sents_1:
        if sent in sents_2:
            counter += 1
    sents_similarity=counter/(math.log(len(sents_1))+math.log(len(sents_2)))
    return sents_similarity

3、萊文斯坦距離(編輯距離)

萊文斯坦距離,又稱Levenshtein距離,是編輯距離(edit distance)的一種。是描述由一個字串轉化成另一個字串最少的編輯操作次數,其中的操作包括插入刪除替換。

舉例:

  • 例如將kitten一字轉成sitting:
  • sitten(k替換爲→s)
  • sittin (e替換爲→i)
  • sitting (添加→g)
  • 那麼二者的編輯距離爲3。

使用python_Levenshtein包進行計算,包下載版本爲:python_Levenshtein-0.12.0-cp36-cp36m-win_amd64.whl

然後安裝:pip install python_Levenshtein-0.12.0-cp36-cp36m-win_amd64.whl 

代碼實現:

import Levenshtein
s1='kitten'
s2='sitting'
lev_distance=Levenshtein.distance(s1,s2)
print(lev_distance)

4、萊文斯坦比

萊文斯坦比計算公式  r = (sum - ldist) / sum, 其中sum是指str1 和 str2 字串的長度總和,ldist是類編輯距離。

注意:這裏的類編輯距離不是3中所說的編輯距離,3中三種操作中每個操作+1,而在此處,刪除、插入依然+1,但是替換+2 。這樣設計的目的:ratio('a', 'c'),sum=2,按3中計算爲(2-1)/2 = 0.5,’a','c'沒有重合,顯然不合算,但是替換操作+2,就可以解決這個問題。

代碼實現:

5、漢明距離

要求str1和str2必須長度一致。是描述兩個等長字串之間對應位置上不同字符的個數

代碼實現:

import Levenshtein
s1='abc'
s2='cba'
lev_distance=Levenshtein.hamming(s1,s2)
print(lev_distance)
#結果輸出爲2

6、Jaro距離(Jaro Distance)

Jaro Distance 算法是一種計算兩個字符串之間相似度的方法。

計算公式:

其中,m爲S1和S2的匹配長度(即匹配的字符數),t是換位的數目;如果m=0,則dj=0。

兩個分別來自S1和S2的字符如果相距不超過

時,我們就認爲這兩個字符串是匹配的;而這些相互匹配的字符則決定了換位的數目t,簡單來說就是不同順序的匹配字符的數目的一半即爲換位的數目t。

舉例:MARTHA與MARHTA的字符都是匹配的,但是這些匹配的字符中,T和H要換位才能把MARTHA變爲MARHTA,那麼T和H就是不同的順序的匹配字符,t=2/2=1。那麼這兩個字符串的Jaro Distance即爲:

代碼實現:

import Levenshtein
s1='MARTHA'
s2='MARHTA'
lev_distance=Levenshtein.jaro(s1,s2)
print(lev_distance)
#結果輸出爲0.9444

7、Jaro-Winkler距離(Jaro-Winkler Distance

Jaro-Winkler Distance給予了起始部分就相同的字符串更高的分數,他定義了一個前綴p。

計算公式:

其中,dj是兩個字符串的Jaro Distance,是前綴的相同的長度,但是規定最大爲4,p則是調整分數的常數,規定不能超過0.25,不然可能出現dw大於1的情況,Winkler將這個常數定義爲0.1。

舉例:6中提及的MARTHA和MARHTA的Jaro-Winkler Distance爲:dw = 0.944 + (3 * 0.1(1 − 0.944)) = 0.961

代碼實現:

import Levenshtein
s1='MARTHA'
s2='MARHTA'
lev_distance=Levenshtein.jaro_winkler(s1,s2)
print(lev_distance)
#結果輸出爲0.9611

 

 

參考:

1、Levenshtein全部函數鏈接

2、Jaro–Winkler distance鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章