`

文本相似度之LSI

阅读更多

1.VSM简介

     空间向量模型VSM,是将文本表示成数值表示的向量。在使用VSM做文本相似度计算时,其基本步骤是:

    1)将文本分词,提取特征词s:(t1,t2,t3,t4)

    2)将特征词用权重表示,从而将文本表示成数值向量s:(w1,w2,w3,w4),权重表示的方式一般使用tfidf

    3)计算文本向量间的余弦值,判断文本间的相似度

缺点:空间向量模型以词袋为基础,没有考虑词与词间的关系,近义词等。

 

 2.LSI介绍

     潜在语义索引(Latent Semantic Indexing,以下简称LSI),有的文章也叫Latent Semantic  Analysis(LSA)。是一种简单实用的主题模型。LSI是基于奇异值分解(SVD)的方法来得到文本的主题的。其推导过程如下图:(参考:http://www.cnblogs.com/pinard/p/6251584.html ,https://www.cnblogs.com/pinard/p/6805861.html)

     

 

使用LSI计算文本相似度的基本过程:

    1).和VSM一样,得到文本的tfidf值的向量表示 

    2).做SVD分解,得到Uk词和词义之间的相关性。Vk文本和主题的相关性。

    3).利用文本主题矩阵计算文本的相似度(通过余弦值)

 

3.应用

1.准备数据

    数据分为两部分(Idx2ID,questionList)

   idx2ID:保存数据库中的ID及ID在文件中的下标,例如({0:100,1:101,2:102} 其中0,1,2为下标;100,102,103为数据库中的ID值)

  questionList:保存的是数据库中问题切词后的二维数组,例如[['我','跑路','了'],['你',‘很’,‘不开心’]]

  其中questionList中的数组下标与idx2ID中的下标一 一对应,及数据库中的保存记录为:(id:100,question:‘我跑路了’)

 

 

import re
from tqdm import tqdm
import os
import pickle
import jieba
import pymysql
import pandas as pd 

'''
从数据库获取训练数据
'''

#清洗数据,去掉停用词并进行jieba分词
stwlist = pickle.load(open('stop_word.pkl','rb'))
def getTrainData(sentence):
    sentence=re.sub(r'[a-zA-Z0-9]+','', sentence)
    wordList = jieba.cut(sentence.strip(), cut_all=False)
    new_wordList = []
    for word in wordList:
        if word not in stwlist:
            new_wordList.append(word)
    return new_wordList

def get_ID_Question():
    aldb = pymysql.connect(host='xx.xx.xx.xx', port=3306, user='user1', passwd='123456', db="testdb", charset='utf8')
    IdList = []
    QuestionList = []
    with pymysql.cursors.SSCursor(aldb) as cursor:
        cursor.execute('select id,question from test')
        while True:
            rs = cursor.fetchone()
            if not rs:
                break
            id= rs[0]
            question = rs[1]
            IdList.append(id)
            QuestionList.append(getTrainData(question))
    #保存数据库中id及id在文件中对应的下标
    Idx2ID = {}
    for index, ID in enumerate(IdList):
        Idx2ID[index] = ID

    return Idx2ID,QuestionList

def save_ID_Question():
    Idx2ID_path = './cache/Idx2ID.pkl'
    QuesttionData_path='./cache/traindata.pkl'

    Idx2ID, QuestionList= get_ID_Question()

    #保存数据
    pickle.dump(Idx2ID, open(Idx2ID_path,'wb'))
    pickle.dump(QuestionList, open(QuesttionData_path, 'wb'))
    print('save data result!')

if __name__=='__main__':
    save_ID_Question()

 2.训练模型

#建立lsi模型,并将生成的LSI模型保存
def lsi_model(num_topics):
    lsi_model_dictionary = './cache/lsi_dictionary.pkl'
    lsi_model_lsi = './cache/model.lsi'
    lsi_model_index = './cache/lsimodel.index'
    cut_question_path = r'./cache/traindata.pkl'
    if os.path.exists(lsi_model_dictionary):
        dictionary = pickle.load(open(lsi_model_dictionary,'rb'))
        lsi = models.LsiModel.load(lsi_model_lsi)
        index = similarities.MatrixSimilarity.load(lsi_model_index)
    else:
        textdata1 = pickle.load(open(cut_question_path, 'rb'))
        #生成词典
        dictionary = corpora.Dictionary(textdata1)
        print('dictionary prepared!')
        corpus = [dictionary.doc2bow(text) for text in textdata1]
        print('corpus prepared!')
        #计算tfidf
        tfidf = models.TfidfModel(corpus)
        print('tfidf prepared!')
        corpus_tfidf = tfidf[corpus]
        #训练LSI
        lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics = num_topics)
        print('lsi model prepared!')
        corpus_lsi = lsi[corpus_tfidf]
        #生成引用
        index = similarities.MatrixSimilarity(corpus_lsi)
        print('index prepared!')
        pickle.dump(dictionary, open(lsi_model_dictionary,'wb'))
        lsi.save(lsi_model_lsi)
        index.save(lsi_model_index)
    return dictionary, lsi, index

 3.测试

class test(object):
    def __init__(self):
        #加载模型数据
        self.dictionary = pickle.load(open('./cache/lsi_dictionary.pkl','rb'))
        self.lsi = models.LsiModel.load('./cache/model.lsi')
        self.index = similarities.MatrixSimilarity.load('./cache/lsimodel.index')
        self.stop_word = pickle.load(open('./stop_word.pkl','rb'))
        self.idx2ID = pickle.load(open('./cache/idx2ID.pkl','rb'))
    #清洗输入问题,并切词
    def deal_query(self,query):
        query = re.sub(r'[a-zA-Z0-9]+','',query)
        query_ques = jieba.cut(query.strip(), cut_all=False)
        new_wordList = []
        for word in query_ques:
            if word not in self.stop_word:
                new_wordList.append(word)
        return new_wordList

    #清洗匹配到的问题
    def clean_question(self, question):
        question = re.sub('律师', '', question)
        ques = pseg.cut(question)
        for word in ques:
            if word.flag == 'nr1' or word.flag == 'nr2' or word.flag == 'nr':
                keys = word.word
                question = re.sub(keys, '', question)
        return question

   #从数据库获取匹配到的问答对
    def get_answer(self,idx_set):
        question_set = []
        answer_set = []
        db = pymysql.connect(host='xx.xx.xx.x', port=3306, user='user1', passwd='123456', db="testdb", charset='utf8')
        for i in idx_set:
            ID = self.idx2ID[i]
            # print(ID)
            cursor = db.cursor()
            cursor.execute('select question,answer from test where id=%d;' %ID)
            db.commit()
            result = cursor.fetchone()
            if result:
                question = self.clean_question(result[0])
                question_set.append(question)
                answer = self.clean_answer(result[1])
                answer_set.append(answer)
        db.close()
        return question_set,answer_set
    #匹配
    def match(self,query):
        query_ques = self.deal_query(query)
        query_bow = self.dictionary.doc2bow(query_ques)
        query_lsi = self.lsi[query_bow]
        #计算余弦相似度,获取前3个最匹配的值
        sims = self.index[query_lsi]
        sort_sims = sorted(enumerate(sims), key=lambda item: -item[1])
        idx_set = [i[0] for i in sort_sims[:3]]
        sim_value = [i[1] for i in sort_sims[:3]]

        question_set,answer_set = self.get_answer(idx_set)

        return question_set,answer_set,sim_value

    def request(self,query):
        import json
        question_set,answer_set,sim_value = self.match(query)
        #相似度小于0.65的问题丢弃
        if sim_value[0] < 0.65:
            print("we have no match answer")
            return None
        i=0
        question_answer={}
        while i<len(question_set):
            q=question_set[i]
            a=answer_set[i]
            if len(q) > 2 and len(a) > 2:
                question_answer[q]=a
            if len(question_answer)>3:
                break
            i+=1
        # print_result2 = {k: v for k, v in question_answer.items() }
        print(len(question_answer))
        print(question_answer)
        return json.dumps(question_answer, ensure_ascii=False)

    #清洗答案数据
    def clean_answer(self,answer):
        # 将如果有多个回答,取长度最长的一个回答
        answer_sent = answer.strip().split('NEXT_ANS')
        if len(answer_sent) > 1:
            answer_len = [len(ans) for ans in answer_sent]
            inx = answer_len.index(max(answer_len))
            answer = answer_sent[inx]
        answer = re.sub('[,]+', ',', answer)
        answer = re.sub('[。]+', '。', answer)
        answer = re.sub('[.]+', '', answer)
        answer = re.sub('[,]+', ',', answer)

        from zhon.hanzi import punctuation
        # 去除 '\nNEXT_ANS'
        answer = answer.replace('NEXT_ANS', '')
        duels = [x + y for x in punctuation
                 for y in punctuation]
        pattern1 = re.compile('^[%s]' % punctuation)
        pattern2 = re.compile('[%s]$' % punctuation)
        pattern3 = re.compile('\[.*?\]')

        # 去除[]中的内容
        answer = pattern3.sub('', answer)

        # 去除空格
        answer = answer.split()
        answer = ''.join(answer)

        # 去除【】符号
        answer = answer.replace('【', '')
        answer = answer.replace('】', '')

        # 去除《》符号不全的句子中的《》
        if (answer.count('《') != answer.count('》')):
            answer = answer.replace('《', '')
            answer = answer.replace('》', '')

        # 去除‘去),张三你好’类型的错误
        delCStr = '《》()&%¥#@!{}【】'
        if (answer[2] in delCStr):
            answer = answer[2:]

        # 去除\n \\n \u3000\u30005 \xa0 \r &quot
        answer = re.sub(r'\\u3\d{3,4}', '', answer)
        answer = re.sub(r'\\n', '', answer)
        answer = re.sub(r'\\xa0', '', answer)
        answer = re.sub(r'\\r', '', answer)
        answer = re.sub(r'&quot', '', answer)
        #去除电话
        answer = re.sub(r'电话:', '', answer)
        answer = re.sub(r'电话\d{11}', '', answer)  # 电话13466352858
        answer = re.sub(r'电话\d{3}\-\d{8}', '', answer)  # 电话010-68812000
        answer = re.sub(r'\d{3}\-\d{8}', '', answer)  # 010-68812000
        answer = re.sub(r'0\d{10}', '', answer)  # 01065083250
        answer = re.sub(r'1[3458]\d{9}', '', answer)  # 手机号码
        answer = re.sub(r'[一二三四五六七八九零]{11,}', '', answer)  # 一三八二零二八八一二六

        # 去除QQ
        answer = re.sub(r'QQ:[1-9]\d{4,10}', '', answer)
        answer = re.sub(r'qq:[1-9]\d{4,10}', '', answer)
        answer = re.sub(r'QQ[1-9]\d{4,10}', '', answer)
        # 邮箱
        answer = re.sub(r'[0-9]*@.*.com', '', answer)
        # answer = re.sub(r'[1-9]\d{4,10}', '', answer)
        # 去除邮箱
        answer = re.sub(r'E-mail:', '', answer)
        answer = re.sub(r'email:', '', answer)
        answer = re.sub(r'电子邮箱', '', answer)
        answer = re.sub(r'邮箱', '', answer)
        answer = re.sub(r'[\w\.-]+@([\w]+\.)+[a-z]{2,3}', '', answer)
        # 去除网址
        answer = re.sub(r'个人网址:', '', answer)
        answer = re.sub(r'网址:', '', answer)
        answer = re.sub('[http|https|www].*[com|cn|html|0-9|a-z]', '', answer)
        # http://www51wfcom/zxzx/ZixunMainViewjsp?ID=bd84d23a2ec1fd73012ec2a422e40044

        answer = re.sub(r'[a-zA-Z]*', '', answer)

        # 特殊符号
        answer = re.sub(r'&.t', '', answer)
        answer = re.sub(r'&#215', '', answer)
        # 去除人名
        address = ''
        ans_list = pseg.cut(answer)
        for word in ans_list:
            # 去除不含国字的地名
            '''
            if (word.flag == 'ns' and not (word.word.find('国') > -1)):
                keys = word.word
                answer = re.sub(keys, '', answer)
                continue
            '''
            # 去除姓名:nr 人名,nr1 汉语姓氏,nr2 汉语名字
            if word.flag == 'nr1' or word.flag == 'nr2' or word.flag == 'nr':
                keys = word.word
                answer = re.sub(keys, '', answer)
        # 去除重复标点符号
        for d in duels:
            while d in answer:
                answer = answer.replace(d, d[0])

        # 去除开头标点符号
        if answer[0]!='《':
            answer = pattern1.sub('', answer)

        # 结尾加句号
        answer = pattern2.sub('。', answer)
        if pattern2.search(answer) is None:
            answer = answer + '。'
        else:
            answer = pattern2.sub('。', answer)

        return answer

if __name__=='__main__':
    # lsi_model(800)
    tst=test()
    while True:
        text=input('输入问题:')
        st=time.time()
        tst.request(text)
        end=time.time()
        print(end-st)

 

 

  • 大小: 473.6 KB
分享到:
评论

相关推荐

    中文文本相似度在商业网络中的应用.pdf

    目前,中文文本相似度计算有多种算法,如基于向量空间模型(VSM)和隐性语义标引(LSI)的方法。VSM将文本表示成词频向量,然后计算词频向量之间的夹角余弦来获得文本相似度。LSI也基于向量空间技术,使用矩阵理论中...

    文本挖掘从小白到精通(四)---文本相似度检索1

    LSI(Latent Semantic Indexing)是LSA的一种应用,可以用于文本相似度检索,因为它能揭示文本间的关系,即使这些文本在表面上看起来并不相同。 Word2Vec是另一种强大的工具,它通过神经网络学习词的分布式表示。...

    Python实现简单的文本相似度分析操作详解

    在Python中实现文本相似度分析,常常涉及到自然语言处理(NLP)技术,这包括了对文本的预处理,如分词,以及使用特定的算法来量化文本间的相似度。本例中,主要使用了两个关键库:jieba用于中文分词,gensim则用于...

    文本相似度算法,首先对文本分词,然后计算词频,生成词频向量,使用余弦相似度算法进行计算

    文本相似度算法是自然语言处理领域中的重要技术,主要用于判断两段或多段文本之间的相似程度。在信息检索、推荐系统、问答系统等多个场景下都有广泛应用。在这个过程中,我们通常会经历以下几个关键步骤: 1. **...

    文本域相似度计算的一种自适应方法

    在进行文本相似度计算时,传统的TF-IDF方法可以用来获取文本中单词的权重,而LSI则用于发现文本中的主题或概念结构。为了实现自适应计算,文章中首先使用TF-IDF方法得到文本中单词的频率,然后通过降维技术减少数据...

    2022管理层讨论与分析 MD&amp;A文本及情感分析

    [2] MD&A文本相似度(与上一年相比):关于中文文本相似度计算,首先使用 结巴分词对文本进行处理,分词过程中去掉阿拉伯数字、标点符号、图片表格。接下来使用 潜在语义索引(Latent Semantic Indexing, LSI)余弦相...

    Lsi.rar_LSI LINGPIPE_lsi_lsi...java

    LSI(Latent Semantic Indexing,潜在语义索引)是一种自然语言处理技术,用于信息检索和文本挖掘。它通过分析文档集合中的词汇关系来捕捉文档的潜在主题,从而提高搜索精度。在Java环境中,我们可以利用如Apache ...

    lsi.rar_LSI matlab _lsi_lsi in matlab_matlab LSI

    LSI,全称为Latent Semantic Indexing(潜在语义索引),是一种在信息检索和文本挖掘领域广泛应用的技术。它通过分析文档集合中的词汇关系来理解文档的潜在主题,从而提高信息检索的精度和效率。本资源包含LSI在...

    Python人工智能之路 jieba gensim 最好别分家之最简单的相似度实现.pdf

    总结来说,Python的人工智能之路中,jieba库负责对中文文本进行有效的分词处理,gensim库则负责将这些分词转化为数学模型,并利用LSI等算法计算文本之间的语义相似度。这两个库的结合使用,使得计算机能更好地理解和...

    Text Similarity in Vector Space Models: A Comparative Study

    ### 文本相似度在向量空间模型中的比较研究 #### 摘要与背景 本文主要探讨了在自然语言处理领域自动测量语义文本相似度的重要性,并通过对比不同类型的向量空间模型(Vector Space Model, VSM)评估其在解决实际...

    文本挖掘聚类分析空间向量模型资料1

    在向量空间模型中,文本之间的相似度通常通过余弦相似度计算,这有助于识别文档之间的主题关联。例如,“基于向量空间模型的文本分类系统研究与实现.nh”可能涵盖了如何构建这样的模型,以及如何利用模型进行文本...

    060-文本大数据分析_20201019_1

    矩阵的行在经过LSI处理后,代表了词项在新的语义空间中的表示,有助于改善文本的相似度计算和信息检索效果。 在【部分内容】中,提到了文本大数据分析的三个核心任务:文本表达、文本匹配和文本生成。 1. **文本...

    基于潜在语义索引的文本浏览机制

    在语义空间中,LSI通过计算向量之间的余弦相似度来衡量文本与文本、项与项、项与文本之间的相似度,这有助于更准确地识别文本之间的语义关联,从而提高信息检索和文本分类的性能。 ### 概念标注 概念标注是另一种...

    文档相似度计算

    总结来说,“文档相似度计算”涵盖了从文本预处理到向量化表示,再到相似度度量的整个流程,涉及多种方法和技术。通过源码和工具的运用,我们可以有效地分析和比较不同文档之间的相似性。对于IT从业者而言,掌握这些...

    文本分类 特征选择 VSM

    - **相似度计算**:通过计算文档向量之间的余弦相似度,可以衡量文档间的相似程度,有助于分类决策。 - **降维可能性**:通过主成分分析(PCA)、潜在语义索引(LSI)等技术,可以进一步降低向量维度,减少计算...

    gensim-3.8.3-cp27-cp27m-win32.whl.zip

    《gensim 3.8.3:Python中的主题建模与文本相似度工具》 gensim是一个开源的Python库,专为处理大型文本语料库而设计,它提供了丰富的工具来执行主题建模和计算文本之间的相似度。在这个场景中,我们关注的是gensim...

    ChineseSTS-master.zip

    《西电中文文本语义相似度语料集》是一个专门针对中文文本的语义相似度研究的重要资源。在自然语言处理领域,语义相似度是衡量两个文本在语义上是否接近的关键指标,广泛应用于信息检索、问答系统、机器翻译、情感...

    Python人工智能之路 jieba gensim 最好别分家之最简单的相似度实现

    文章主要介绍了如何使用jieba和gensim这两个库来实现简单的自然语言处理和文本相似度计算。首先,通过jieba库对中文语句进行分词,得到一个个独立的词汇单元。然后,借助于gensim库,可以构建一个词袋模型(Bag of ...

    文本分类聚类.docx

    文本聚类的目标是将文本集合中的文档分组,使同一簇内的文本内容具有高相似度,而不同簇之间的文本差异较大。 - **分类**是有监督学习的过程,需要已知的标记数据作为训练集,以构建模型预测新数据的类别。文本分类...

    LSI模型在信息检索中的应用

    在检索过程中,通过计算查询向量与文档向量之间的相似度(如余弦相似度),可以找到最相关的文档。 4. **使用PRF技术改进检索结果**:为了进一步提高检索质量,可以采用PRF(Pseudo Relevance Feedback,伪相关反馈...

Global site tag (gtag.js) - Google Analytics