編寫文本相似性分析程序

餘弦相似度,又稱爲餘弦相似性,是通過計算兩個向量的夾角餘弦值來評估向量間的相似度。

計算兩個 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