Logo

郎哥编程

编写文本相似性分析程序

2022-03-01 293

余弦相似度,又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估向量间的相似度。

计算两个n维向量夹角余弦值的计算公式为:

01.png

其中A*B是A和B向量的点积,|A|*|B|是向量A和B模长的积。

1、相似度分析程序编码

余弦相似度分析工作流程图如下:

02.png

多文档词袋数据已经建立,待分析的文档数据需要进行中文分词,形成单文档词袋数据。相似性分析程序对传入的单文档词袋数据,与多文档词袋数据进行逐一分析,并输出一个数组,数组的元素为单文档词袋数据与比对文档词袋数据的夹角余弦值。

在项目根目录下建立文件夹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类对新文档进行相似性分析,输出结果为新文档与原文当的相似度。


代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论