当前位置: 首页 > 工具软件 > WMD > 使用案例 >

中文短文本相似度:WMD

萧阳波
2023-12-01

开篇


句子相似是目前我做问句匹配的基础。


这是我尝试使用词向量,以一种无监督方法去计算两个句子相似度的第二种方法。第一种方法,我尝试使用词向量的加权平均生成句向量来计算句子间的相似度,效果很一般,之后我会尝试使用不同的加权方法再次计算。有机会我会连着代码一起放出来。
当然我还使用了三种不同的深度学习方法来计算相似度,之后都会以代码讲解的方式呈现。本博客没有使用任何公司的数据,也未集成到公司的任何系统中,属于学术型文章开源。


WMD


word mover’s distance 是一种计算句子之间距离的方法,距离越小,相似度越高。看了网上几篇博客,基本是这边抄一下,那边抄一下,内容非常得凌乱。这边也放一篇博客,等我读过原始论文,再来这篇博客来补充相关的理论知识,现在这篇博客希望通过代码让你更快的构建自己的wmd计算函数。迅速实战。


词向量


首先我们还是需要借助词向量,你可以自己下载别人训练好的词向量,或者自己使用gensim训练词向量
关于词向量的训练,我这边不再重复,使用gensim只要几行代码,如果没有相关的经验,可以参考我之前的博客。


WMDdistance


先放出相关的代码,博客的最后我会放出完整的代码,如果有什么疑问欢迎留言。数据是公司的,不会公开,但是有其他数据可以替换。不影响代码的运行。


def wmd(sent1, sent2):
    sent1 = word_cut(sent1)
    sent2 = word_cut(sent2)
    model = KeyedVectors.load_word2vec_format(os.path.join(data_dir, "Word2VecModel_small.vector"))
    model.init_sims(replace=True)
    #这边是归一化词向量,不加这行的话,计算的距离数据可能会非常大
    distance = model.wmdistance(sent1,sent2)
    return distance

词向量是一定要加载的。
中文当然是要分词的,这里我使用的是哈工大的分词工具,下面我放出我的代码,这是需要加载的一下模型和词典。
data_dir = "C:\\Users\\d84105613\\PycharmProjects\\Ai_qa\\data"
LTP_DATA_DIR = 'C:\\Users\\d84105613\\ltp_data'
cws_model_path = os.path.join(LTP_DATA_DIR, 'cws.model')
segmentor = Segmentor()  # 初始化实例
segmentor.load_with_lexicon(cws_model_path, os.path.join(data_dir,'wordDictupper.txt'))  # 加载模型

#停用词载入
stopwords = []
stopword = open(os.path.join(data_dir,'stopwords_zh.txt'),'rt',encoding='utf-8')
for line in stopword:
    stopwords.append(line.strip())

分词的时候记得把停用词也给去了
def word_cut(sentence):
    words = segmentor.segment(sentence)
    # segmentor.release()
    words = list(words)
    # print(len(set(words)))
    key = [",", "?", "[", "]"]
    words = [c for c in words if c not in punctuation]
    words = [c for c in words if c not in key]
    words = [c for c in words if c not in stopwords]
    return words


搜索相似句子


这边就是问答系统一个简单的功能组件了,给出一个你要查询的句子,在语料库里搜索出最相似的几个句子。感谢gensim提供的库函数。
def get_top_n(document,query,num_best):
    corpus = [word_cut(i) for i in document]
    model = KeyedVectors.load_word2vec_format(os.path.join(data_dir, "Word2VecModel_small.vector"))
    instance = WmdSimilarity(corpus, model, num_best)
    query = word_cut(query)
    sims = instance[query]
    for i in range(num_best):
        print(sims[i][1])
        print(document[sims[i][0]])

 


完整代码
import os
from pyltp import Segmentor
from zhon.hanzi import punctuation
from gensim.models import KeyedVectors
from gensim.similarities import WmdSimilarity

data_dir = "C:\\Users\\d84105613\\PycharmProjects\\Ai_qa\\data"
LTP_DATA_DIR = 'C:\\Users\\d84105613\\ltp_data'
cws_model_path = os.path.join(LTP_DATA_DIR, 'cws.model')
segmentor = Segmentor()  # 初始化实例
segmentor.load_with_lexicon(cws_model_path, os.path.join(data_dir,'wordDictupper.txt'))  # 加载模型

#停用词载入
stopwords = []
stopword = open(os.path.join(data_dir,'stopwords_zh.txt'),'rt',encoding='utf-8')
for line in stopword:
    stopwords.append(line.strip())

def read_data_sets(train_dir):
    s1 = []
    s2 = []
    for line in open(train_dir, encoding='utf-8'):
        l = line.strip().split("¥")
        if len(l) < 2:
            continue
        s1.append(l[0])
        s2.append(l[1])
    return s1, s2

def word_cut(sentence):
    words = segmentor.segment(sentence)
    # segmentor.release()
    words = list(words)
    # print(len(set(words)))
    key = [",", "?", "[", "]"]
    words = [c for c in words if c not in punctuation]
    words = [c for c in words if c not in key]
    words = [c for c in words if c not in stopwords]
    return words


def wmd(sent1, sent2):
    sent1 = word_cut(sent1)
    sent2 = word_cut(sent2)
    model = KeyedVectors.load_word2vec_format(os.path.join(data_dir, "Word2VecModel_small.vector"))
    model.init_sims(replace=True)
    distance = model.wmdistance(sent1,sent2)
    return distance

def get_top_n(document,query,num_best):
    corpus = [word_cut(i) for i in document]
    model = KeyedVectors.load_word2vec_format(os.path.join(data_dir, "Word2VecModel_small.vector"))
    instance = WmdSimilarity(corpus, model, num_best)
    query = word_cut(query)
    sims = instance[query]
    for i in range(num_best):
        print(sims[i][1])
        print(document[sims[i][0]])

输出
0.8867670409833355
修改采购计划当前处理人
0.856070758049195
修改BPA当前处理人
0.8339566600760685
缺陷修改当前处理人
0.8040727679959436
修改变更单当前处理人
0.7797357960999256
修改单据当前处理人

Process finished with exit code 0

 


相关博客代码
补充
之前的代码跑一个批次的数据,大概是6万条要40秒,后续做了一些优化,大概跑6万11秒左右
def overlap(list1,list2):
    temp = [i for i in list1 if i in list2]
    return len(temp)/len(list1)


def fast_top_n(document, query, num_best):
    doc = [word_cut(i) for i in document]
    query = word_cut(query)
    corpus=[]
    document1 = []
    for i,j in enumerate(doc):
        if overlap(query,j) > 0.25:
            corpus.append(doc[i])
            document1.append(document[i])
    model = KeyedVectors.load_word2vec_format(os.path.join(data_dir, "Word2VecModel_small.vector"))
    instance = WmdSimilarity(corpus, model, num_best)
    sims = instance[query]
    for i in range(num_best):
        print(sims[i][1])
        print(document1[sims[i][0]])

          
      
---------------------
作者:Ding_xiaofei
来源:CSDN
原文:https://blog.csdn.net/Ding_xiaofei/article/details/81034058
版权声明:本文为博主原创文章,转载请附上博文链接!

 类似资料: