自然語言處理(NLP)語義分析 文字相似度

2021-09-24 20:57:40 字數 4278 閱讀 3063

​ 在做自然語言處理的過程中,我們經常會遇到需要找出相似語句的場景,或者找出句子的近似表達,這時候就需要把類似的句子歸到一起,這裡面就涉及到句子相似度計算的問題。

句子相似度計算一共歸類了以下幾種方法:

下面來一一了解一下這幾種演算法的原理和 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 的乙個階段,可應用於機器翻譯 摘要形成 資訊檢索等等,個人認為,自然語言處理是一門很複雜的跨學科技術,其難點在於人類是富有思維的,人的語言寄託人的思想,因此很難準確處理。...