在做自然語言處理的過程中,我們經常會遇到需要找出相似語句的場景,或者找出句子的近似表達,這時候就需要把類似的句子歸到一起,這裡面就涉及到句子相似度計算的問題。
句子相似度計算一共歸類了以下幾種方法:
下面來一一了解一下這幾種演算法的原理和 python 實現。
編輯距離計算
編輯距離,英文叫做 edit distance,又稱 levenshtein 距離,是指兩個字串之間,由乙個轉成另乙個所需的最少編輯操作次數,如果它們的距離越大,說明它們越是不同。許可的編輯操作包括將乙個字元替換成另乙個字元,插入乙個字元,刪除乙個字元。
例如我們有兩個字串:string 和 setting,如果我們想要把 string 轉化為 setting,需要這麼兩步:
所以它們的編輯距離差就是 2,這就對應著二者要進行轉化所要改變(新增、替換、刪除)的最小步數。
那麼用 python 怎樣來實現呢,我們可以直接使用 distance 庫:
#編輯距離
import distance
defedit_distance
(s1, s2)
:return distance.levenshtein(s1, s2)
strings =
['你在幹什麼'
,'你在幹啥子'
,'你在做什麼'
,'你好啊'
,'我喜歡吃香蕉'
]target =
'你在幹啥'
results =
list
(filter
(lambda x: edit_distance(x, target)
<=
2, strings)
)print
(results)
'''['你在幹什麼', '你在幹啥子']
'''
通過這種方式我們可以大致篩選出類似的句子,但是發現一些句子例如「你在做什麼」 就沒有被識別出來,但他們的意義確實是相差不大的,因此,編輯距離並不是乙個好的方式,但是簡單易用。
傑卡德係數計算
傑卡德係數,英文叫做 jaccard index, 又稱為 jaccard 相似係數,用於比較有限樣本集之間的相似性與差異性。jaccard 系數值越大,樣本相似度越高。
實際上它的計算方式非常簡單,就是兩個樣本的交集除以並集得到的數值,當兩個樣本完全一致時,結果為 1,當兩個樣本完全不同時,結果為 0。
演算法非常簡單,就是交集除以並集,下面我們用 python **來實現一下:
#傑卡德係數計算
from sklearn.feature_extraction.text import countvectorizer
import numpy as np
defjaccard_similarity
(s1, s2)
:def
add_space
(s):
return
' '.join(
list
(s))
# 將字中間加入空格
s1, s2 = add_space(s1)
, add_space(s2)
# 轉化為tf矩陣
cv = countvectorizer(tokenizer=
lambda s: s.split())
corpus =
[s1, s2]
vectors = cv.fit_transform(corpus)
.toarray(
)# 求交集
numerator = np.
sum(np.
min(vectors, axis=0)
)# 求並集
denominator = np.
sum(np.
max(vectors, axis=0)
)# 計算傑卡德係數
return
1.0* numerator / denominator
s1 =
'你在幹嘛呢'
s2 =
'你在幹什麼呢'
print
(jaccard_similarity(s1, s2)
)'''
0.5714285714285714
'''
這個數值越大,代表兩個字串越接近,否則反之,因此我們也可以使用這個方法,並通過設定乙個相似度閾值來進行篩選。
tf 計算
第三種方案就是直接計算 tf 矩陣中兩個向量的相似度了,實際上就是求解兩個向量夾角的余弦值,就是點乘積除以二者的模長,公式如下:
cosθ=a·b/|a|*|b|上面我們已經獲得了 tf 矩陣,下面我們只需要求解兩個向量夾角的余弦值就好了,**如下:
from sklearn.feature_extraction.text import countvectorizer
import numpy as np
from scipy.linalg import norm
deftf_similarity
(s1, s2)
:def
add_space
(s):
return
' '.join(
list
(s))
# 將字中間加入空格
s1, s2 = add_space(s1)
, add_space(s2)
# 轉化為tf矩陣
cv = countvectorizer(tokenizer=
lambda s: s.split())
corpus =
[s1, s2]
vectors = cv.fit_transform(corpus)
.toarray(
)# 計算tf係數
return np.dot(vectors[0]
, vectors[1]
)/(norm(vectors[0]
)* norm(vectors[1]
))s1 =
'你在幹嘛呢'
s2 =
'你在幹什麼呢'
print
(tf_similarity(s1, s2)
)'''
#使用np.dot() 方法獲取向量的點乘積,然後通過 norm() 方法獲取向量的模長,經計算得到二者的 tf 係數
0.7302967433402214
'''
tfidf 計算
還可以計算 tf-idf 係數,tf-idf 實際上就是在詞頻 tf 的基礎上再加入 idf 的資訊,idf 稱為逆文件頻率。
借助於 sklearn 中的模組 tfidfvectorizer 來實現,**如下:
from sklearn.feature_extraction.text import tfidfvectorizer
import numpy as np
from scipy.linalg import norm
deftfidf_similarity
(s1, s2)
:def
add_space
(s):
return
' '.join(
list
(s))
# 將字中間加入空格
s1, s2 = add_space(s1)
, add_space(s2)
# 轉化為tf矩陣
cv = tfidfvectorizer(tokenizer=
lambda s: s.split())
corpus =
[s1, s2]
vectors = cv.fit_transform(corpus)
.toarray(
)# 計算tf係數
return np.dot(vectors[0]
, vectors[1]
)/(norm(vectors[0]
)* norm(vectors[1]
))s1 =
'你在幹嘛呢'
s2 =
'你在幹什麼呢'
print
(tfidf_similarity(s1, s2)
)'''
0.5803329846765686
'''
word2vec 計算
word2vec,顧名思義,其實就是將每乙個詞轉換為向量的過程。可參考word2vec和doc2vec的介紹。
NLP自然語言處理
第1部分自然語言處理入門 1.1自然語言處理入門.mp4 第2部分hmm和crf 1.1crf模型簡介.mp4 1.1hmm模型介紹.mp4 1.2文字處理的基本方法 part1.mp4 2.1新聞主題分類任務 第4步 part2.mp4 第43部分rnn 1.1rnn模型小結.mp4 1.1rnn...
NLP自然語言處理
老實來講這課我一頭霧水滿腦袋問號 import numpy as np from collections import counter counttime 0 def seperate filename totalnum 0 郵件的總數 global counttime i 0 file open ...
NLP自然語言處理相關
近期需要學習一些命名實體識別的知識,記錄一下,以便以後複習 個人理解 目前的理解是,命名實體識別 ner 是自然語言處理 nlp 的乙個階段,可應用於機器翻譯 摘要形成 資訊檢索等等,個人認為,自然語言處理是一門很複雜的跨學科技術,其難點在於人類是富有思維的,人的語言寄託人的思想,因此很難準確處理。...