中文短文本相似度:WMD

开篇

句子相似是目前我做问句匹配的基础。
这是我尝试使用词向量,以一种无监督方法去计算两个句子相似度的第二种方法。第一种方法,我尝试使用词向量的加权平均生成句向量来计算句子间的相似度,效果很一般,之后我会尝试使用不同的加权方法再次计算。有机会我会连着代码一起放出来。
当然我还使用了三种不同的深度学习方法来计算相似度,之后都会以代码讲解的方式呈现。

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

相关博客代码

猜你喜欢

转载自blog.csdn.net/ding_xiaofei/article/details/81034058