最近幫很多本科畢業生做文本數據分析,經常遇到的一個需求是計算文檔相似度。
思路:
-
抽取語料(所有文檔)中的詞語,構建詞典(詞語與數字對應起來)。
-
根據構建的詞典對每個文檔進行重新編碼(將文檔轉化爲向量)。
- 使用餘弦計算相似度
下面的corpus是我在知乎live隨便找到的幾個評論,拿來當做測試的例子。好像數據不怎麼好玩,大家跟着一起湊合湊合吧。
corpus = ['老師講的很好很全面乾貨很多',
'講述的很好乾貨滿滿',
'滿滿的乾貨很實用',
'感謝老師無私的分享啦',
'真水呵呵噠']
構建詞典-學習語料特徵
其實在機器學習裏,學習語料的所有詞語並將其轉化爲數字,這一步驟叫做特徵化。強烈推薦對數據科學感興趣的童鞋學學scikit-learn庫,人工智能咱們小白可能還玩不轉,但是調用封裝好的機器學習算法,淺顯的玩玩機器學習還是沒啥難度的。
在scikit-learn中,涉及到文本數據特徵化的類有sklearn.feature_extraction.text.CountVectorizer 和sklearn.feature_extraction.text.TfidfVectorizer 。我們先以常見的詞頻統計作爲特徵抽取的方式開始探索,由於scikit默認使用英文空格作爲分詞符號,所以處理中文數據前我們要分詞並以空格間隔開來。
from sklearn.feature_extraction.text import CountVectorizer
import jieba
corpus = [' '.join(jieba.lcut(doc))
for doc in corpus]corpus
['老師 講 的 很 好 很 全面 乾貨 很多',
'講述 的 很 好 乾貨 滿滿',
'滿滿的 乾貨 很 實用',
'感謝 老師 無私 的 分享 啦',
'真水 呵呵 噠']
wordcounter = CountVectorizer()
#學習特徵(構建詞典)fit 並轉化爲特徵矩陣。
matrix=wordcounter.fit_transform(corpus)
print(matrix.toarray())
#查看下特徵與詞語對應關係
print(wordcounter.get_feature_names())
[[1 0 0 0 1 1 0 0 0 0 0 1 0]
[0 0 0 0 1 0 0 0 1 0 0 0 1]
[0 0 0 1 1 0 0 0 0 1 0 0 0]
[0 1 0 0 0 0 1 1 0 0 0 1 0]
[0 0 1 0 0 0 0 0 0 0 1 0 0]]
['全面', '分享', '呵呵', '實用', '乾貨',
'很多', '感謝', '無私', '滿滿', '滿滿的',
'真水', '老師', '講述']
計算相似度
這裏使用scikit提供的cosine-similarity函數。
from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(matrix)
array([[1. , 0.28867513, 0.28867513, 0.25 , 0. ],
[0.28867513, 1. , 0.33333333, 0. , 0. ],
[0.28867513, 0.33333333, 1. , 0. , 0. ],
[0.25 , 0. , 0. , 1. , 0. ],
[0. , 0. , 0. , 0. , 1. ]])
我們看到這個矩陣是沿着對角線對稱的,所以我們只需要看第一行。
第一個評論與第一個評論之間的相似度爲1
第一個評論與第二個評論的相似度爲0.28867513
第一個評論與第三個評論的相似度爲0.28867513
第一個評論與第四個評論的相似度爲0.25
第一個評論與第四個評論的相似度爲0
高中數學知識cos相似性計算公式
本以爲自己對這裏很熟悉,結果自己寫cos計算公式時居然出錯了。粘貼到這裏,幫助大家回憶高中知識。(a和b是向量)
#cos相似性計算
def cosVector(x,y):
result1=0.0
result2=0.0
result3=0.0
for i in range(len(x)):
result1 +=x[i]*y[i] #sum(a*b)
result2 +=x[i]**2 #sum(a*a)
result3 +=y[i]**2 #sum(b*b)
return str(result1/((result2*result3)**0.5))
vect1 = [1,0,1]
vect2 = [0,1,0]
vect3 = [1,1,1]
print("vect1與vect2相似度爲:", cosVector(vect1, vect2))
print("vect1與vect3相似度爲:", cosVector(vect1, vect3))
print("vect2與vect3相似度爲:", cosVector(vect2, vect3))
vect1與vect2相似度爲: 0.0
vect1與vect3相似度爲: 0.8164965809277261
vect2與vect3相似度爲: 0.5773502691896258