編寫文本相似性分析程序
餘弦相似度,又稱爲餘弦相似性,是通過計算兩個向量的夾角餘弦值來評估向量間的相似度。
計算兩個 n 維向量夾角餘弦值的計算公式爲:
其中 AB 是 A 和 B 向量的點積,|A||B | 是向量 A 和 B 模長的積。
1、相似度分析程序編碼
餘弦相似度分析工作流程圖如下:
多文檔詞袋數據已經建立,待分析的文檔數據需要進行中文分詞,形成單文檔詞袋數據。相似性分析程序對傳入的單文檔詞袋數據,與多文檔詞袋數據進行逐一分析,並輸出一個數組,數組的元素爲單文檔詞袋數據與比對文檔詞袋數據的夾角餘弦值。
在項目根目錄下建立文件夾 similarities,在 similarities 文件夾下建立 similarity.py 文件。代碼如下:
"""
模塊:相似性分析
功能:
使用餘弦相似度分析文檔間的相似度
"""
import numpy as np
class Similarity():
def __init__(self,corpus):
# corpus爲多文檔詞袋數據
self.corpus = corpus
# 與多文檔詞袋數據逐一分析
# text 待分析的單文檔詞袋數據
def one_analysis(self,text):
# 存儲相似度
sim = []
v_text = self.bow2Vector(text)
for item in self.corpus:
v_item = self.bow2Vector(item)
value = self.consine(np.array(v_text),np.array(v_item))
sim.append(value)
return sim
# 詞袋模型抽取爲向量
def bow2Vector(self,bow):
vect = []
for m in bow:
vect.append(m[1])
return vect
# 計算兩個向量間夾角的餘弦值
def consine(self,v,mv):
# 計算點積
dot = np.dot(v,mv)
# 計算向量v的模長
ma = np.linalg.norm(v)
# 計算向量mv的模長
mb = np.linalg.norm(mv)
# 計算向量v和mv的相似度
return dot/(ma*mb)
Similarity 類的 corpus 爲多文檔詞袋數據,在類初始化時被賦值。one_analysis() 方法採用逐一比對的方式計算向量間夾角的餘弦值,該算法效率比較低下,爲提高計算效率,應採用矩陣運算,後面會採用矩陣運算,進行計算效率的比對分析。
bow2Vector() 方法是從詞袋數據抽取向量,詞袋數據的元素是一個二元組,分別存儲單詞的 ID 和詞頻,該方法抽取詞頻構成詞頻向量。
consine() 方法計算兩個向量間夾角的餘弦值,該值作爲兩個文檔之間的相似度。
若待分析的文檔沒有添加到字典,需要在字典中添加文檔並更新字典數據。在 Dictionary 類添加 update_doc2bow() 方法,該方法添加新文檔到字典,並返回詞袋數據。方法代碼如下:
# 更新字典並輸出詞袋數據
# text爲待分析單文檔
def update_doc2bow(self,text):
texts =[text]
# 更新字典
self.add_documents(texts)
vect = []
# 遍歷字典全部單詞
for key in self.token2id.keys():
if key in text:
'''
若text包含字典單詞,創建二元組(數字ID,詞頻)
添加二元組到詞袋
'''
vect.append((self.token2id[key], text.count(key)))
else:
'''
若text不包含字典單詞,創建二元組(數字ID,0)
添加二元組到詞袋
'''
vect.append((self.token2id[key], 0))
# 詞袋數據按二元組的數字ID排序
vect = sorted(vect, key= lambda x: x[0])
return vect
2、驗證相似度分析程序
編寫一個測試程序,從數據庫讀取 100 條新聞條目,建立字典和多文檔詞袋數據,從中抽取任意 1 條新聞條目進行相似性分析,並輸出整個分析過程耗費的時間。在項目的 test 目錄下建立 simtest.py 文件。代碼如下:
# 相似性分析測試程序
#導入db模塊#
from db import readnews
#導入路徑模塊
from tool import participle as fc
# 導入csv模塊
import csv
#導入路徑模塊
import tool.filepath as path
#導入字典模塊
from corpora.dictionary import Dictionary
#導入分析模塊
from similarities.similarity import Similarity
#導入時間模塊
import datetime
# 計算時間間隔
def get_time_differ(t1,t2):
duringtime = t2 - t1
return duringtime.total_seconds()
# 程序入口
if __name__ == '__main__':
starttime = datetime.datetime.now()
# 讀取前100條新聞條目
t1 = datetime.datetime.now()
data = readnews.query_database_record_limit(0,100)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("從讀取數據庫100條新聞條目,耗時:%.3f秒" % (runsecond))
if data == None:
print("數據庫讀取發生錯誤")
else:
texts = []
t1 = datetime.datetime.now()
# 中文分詞
for text in data:
words = fc.get_particlple(text[1])
texts.append(words)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("中文分詞,耗時:%.3f秒" % (runsecond))
# 創建字典
dictionary = Dictionary()
t1 = datetime.datetime.now()
# 添加文檔到字典
dictionary.add_documents(texts)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("建立字典,耗時:%.3f秒" % (runsecond))
# 提取第1條語料數據進行相似性分析
textwords = texts[0]
t1 = datetime.datetime.now()
simttext = dictionary.update_doc2bow(textwords)
# 從字典讀取詞袋數據
croups = dictionary.doc2bow(texts)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("轉換詞袋數據,耗時:%.3f秒" % (runsecond))
# 初始化相似性分析類
docsim = Similarity(croups)
# 採用文檔逐一分析方式
t1 = datetime.datetime.now()
sim = docsim.one_analysis(simttext)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("相似性分析,耗時:%.3f秒" % (runsecond))
print(sim)
endtime = datetime.datetime.now()
runsecond = get_time_differ(starttime,endtime)
print("總耗時:%.3f秒" % (runsecond))
測試程序從數據庫讀取 100 條新聞條目,並進行中文分詞,分詞完成後創建字典,調用字典對象的 doc2bow() 方法獲取詞袋數據。取第 1 條新聞條目作爲待分析的新文檔,調用字典對象的 update_doc2bow() 方法更新字典並獲取新文檔的詞袋數據,使用 Similarity 類對新文檔進行相似性分析,輸出結果爲新文檔與原文當的相似度。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/AhqmieEkWaovthkAFsFa-A