NLP文本相似度(word2vec)的原理及实现

编程入门 行业动态 更新时间:2024-10-28 14:34:10

NLP<a href=https://www.elefans.com/category/jswz/34/1771357.html style=文本相似度(word2vec)的原理及实现"/>

NLP文本相似度(word2vec)的原理及实现

word2vec的原理及实现方式、训练优化方式前文已做详细介绍,这里不再累赘。这里主要记录NLP文本相似度(word2vec)怎样实现的及实现结果。

怎样实现:在问答系统(KBQA)中输入一个query,比如query为“贪污公款被捕后要还钱吗”?是怎么匹配到知识库中的最相近的一条问题并返回相对应的答案呢?

利用word2vec进行句子相似度计算,是先将输入query,进行分词,把目标句子的各个词的词向量进行相加取平均,从而把任意长的句子表示为固定维度的向量,然后计算两句子词嵌入之间的余弦相似度,进行相似度比较。当然,这么做虽然忽略了句子中的词顺序,但可以作为baseline简单衡量句子相似度计算以及词向量的训练效果。

一般情况下,在平均词嵌入之间求余弦相似性的word2vec方法表现得非常好,据了解比词移距离(Word Mover’s Distance)效果要好。

语料:爬取的问答语料

word2vec实现步骤:全局参数设置、文本预处理、训练词向量、计算相似度、得到最后的文本结果。

全局参数设置:

​主要设置编码方式,文件存储位置,word2vec参数设置。

数据预处理

训练之前需要对文本进行预处理:

  • 读取csv,提取问题及其答案,分词并按行保存到文件中,方便训练词向量。
  • 去停用词,这里由于要保留上下文信息,停用词大都包括标点符号及其他特殊字符。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#停用词+分词+数据预处理import GrobalParament
import jieba
import pandas as pd#去掉回车行
def delete_r_n(line):return line.replace('\r','').replace('\n','').strip()#读取停用词
def get_stop_words(stop_words_dir):stop_words = []with open(stop_words_dir,'r',encoding=GrobalParament.encoding) as f_reader:for line in f_reader:line = delete_r_n(line)stop_words.append(line)stop_words = set(stop_words)return stop_words#jieba精准分词
def jieba_cut(content,stop_words):word_list = []if content != '' and content is not None:seg_list = jieba.cut(content)for word in seg_list:if word not in stop_words:word_list.append(word)return word_list#结巴搜索引擎分词
def jieba_cut_for_search(content,stop_words):word_list = []if content != '' and content is not None:seg_list = jieba.cut_for_search(content)for word in seg_list:if word not in stop_words:word_list.append(word)return word_list#清理不在词汇表中的词语
def clear_word_from_vocab(word_list,vocab):new_word_list = []for word  in word_list:if word in vocab:new_word_list.append(word)return new_word_list#文本预处理第一种方法Pandas
def preprocessing_text_pd(text_dir,after_process_text_dir,stop_word_dir):stop_words = get_stop_words(stop_word_dir)sentences = []df = pd.read_csv(text_dir)for index,row in df.iterrows():print(index)title = delete_r_n(row['title'])word_list = jieba_cut(title,stop_words)df.loc[index,'title'] = ' '.join(word_list)sentences.append(word_list)df.to_csv(after_process_text_dir,encoding=GrobalParament.encoding,index=False)return sentences#文本预处理第二种方法
def preprocessing_text(text_dir,after_process_text_dir,stop_word_dir):stop_words = get_stop_words(stop_word_dir)sentences = []f_writer = open(after_process_text_dir,'w',encoding=GrobalParament.encoding)# count = 0with open(text_dir,'r',encoding=GrobalParament.encoding) as f_reader:for line in  f_reader:line_list = line.split(",")if len(line_list) == 2:line_list2 = delete_r_n(line_list[1])word_list = jieba_cut(line_list2,stop_words)sentences.append(word_list)f_writer.write(line_list[0] + "," + " ".join(word_list) + '\n')f_writer.flush()# count =count + 1# print(count)f_writer.close()return sentencesif __name__ == "__main__":stop_words =get_stop_words(GrobalParament.stop_word_dir)# print(len(stop_words))# print(stop_words)# sentences = preprocessing_text(GrobalParament.test_set_dir, GrobalParament.test_after_process_text_dir,#                                GrobalParament.stop_word_dir)# print(sentences[:10])sentences = preprocessing_text(GrobalParament.test_set_dir,GrobalParament.test_after_process_text_dir,GrobalParament.stop_word_dir)print(sentences[:10])

代码中首先读取语料库文件data/train.csv和data/test.csv,提取目标文本,预处理后保存到data/train_after_process.csv和data/test_after_process.csv,

训练模型:

在理解词向量的训练原理和相关参数设置后,实现部分利用开源工具,过程相对简单。该部分使用gensim对上面预处理后的文本进行词向量的训练:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
#训练模型import GrobalParament
import utils
from gensim.models import word2vecdef train(sentences,model_out_put_path):print('开始训练')model = word2vec.Word2Vec(sentences=sentences,size=GrobalParament.train_size,window=GrobalParament.train_window,min_count=1)model.save(model_out_put_path)print('训练完成')if __name__ == "__main__":# sentences = utils.preprocessing_text(GrobalParament.train_set_dir,GrobalParament.train_after_process_text_dir,GrobalParament.stop_word_dir)# train(sentences,GrobalParament.model_output_path)model = word2vec.Word2Vec.load(GrobalParament.model_output_path)vocab = list(model.wv.vocab.keys())for e in model.most_similar(positive=['借贷'],topn=5):print(e[0],e[1])print(len(vocab))

这里使用默认的训练参数,几个代表性的参数:

  • 词向量的维度size=150
  • 上下文窗口window=5
  • CBOW模型、负采样

代码中首先用LineSentence将语料文本中的内容按行读入为词序列作为训练数据。接着对语料库进行5次迭代,并取词的min_count为1,即所有词汇都参与训练。最后保存训练好的模型。

相似度计算:

这里进行简单测试,从所有问题集作为目标句子,然后从读取测试集中的问题,从目标句子中匹配相似度前五的5个问题。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
#计算相似度import GrobalParament
import utils
from gensim.models.word2vec import Word2Vecdef calc_sim(model_path,train_path,test_path,out_result_path):model = Word2Vec.load(model_path)# vocab = list(model.wv.vocab.keys())#改进vocab = set(model.wv.vocab.keys())# print(len(vocab))# print(vocab[:20])#计算相似度f_write = open(out_result_path,'w',encoding=GrobalParament.encoding)with open(test_path,'r',encoding=GrobalParament.encoding) as f_test_reader:f_test_reader.readline()for test_line in f_test_reader:# print(test_line)test_line = utils.delete_r_n(test_line)test_line_list = test_line.split(',')print('测试集合:' + test_line_list[0])test_word_list = test_line_list[1].split()test_word_list = utils.clear_word_from_vocab(test_word_list,vocab)sim_score = dict()with open(train_path,'r',encoding=GrobalParament.encoding) as f_train_reader:f_train_reader.readline()for train_line in f_train_reader:train_line = utils.delete_r_n(train_line)train_line_list = train_line.split(',')if len(train_line_list) == 2:print('训练集合:' + train_line_list[0])train_word_list = train_line_list[1].split()train_word_list = utils.clear_word_from_vocab(train_word_list,vocab)if len(train_word_list) > 0:sim_score[train_line_list[0]] = model.n_similarity(test_word_list,train_word_list)sim_score = sorted(sim_score.items(),key=lambda d:d[1],reverse=True)#print(sim_score[:5])print('开始计算前5个最相似的')train_doc_num = ''for items in sim_score[:5]:train_doc_num = train_doc_num + items[0] + ' 'f_write.write(test_line_list[0] + ','+train_doc_num.strip() + '\n')f_write.flush()f_write.close()if __name__ =="__main__":calc_sim(GrobalParament.model_output_path,GrobalParament.train_after_process_text_dir,GrobalParament.test_after_process_text_dir,GrobalParament.result_out_path)

load训练好的模型,利用n_similarity进行两个词序列的相似度计算,方法的输入参数是测试集csv文件中 句子分词后的词序列。

得到最后的文本结果:

​​​将​前一步骤得到相似结果的id转化为真正所对应的文本结果。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
#最终结果import GrobalParament
import utils#构建文档字典
def build_dict(file_path):doc_dict = dict()with open(file_path,'r',encoding=GrobalParament.encoding) as f_reader:for line in f_reader:line = utils.delete_r_n(line)line_list = line.split(',')if len(line_list) == 2:doc_dict[line_list[0]] = line_list[1]return doc_dictdef sim_result_out(sim_out_path,test_dict,train_dict,result_path):f_writer = open(result_path,'w',encoding=GrobalParament.encoding)with open(sim_out_path,'r',encoding=GrobalParament.encoding) as f_reader:for line in f_reader:line = utils.delete_r_n(line)line_list = line.split(',')if len(line_list) == 2:test_docid = line_list[0]sim_result = test_docid + ',' + test_dict[test_docid] + '\n'+'***最相似的前20个***\n'train_docid_list = line_list[1].split()for id in train_docid_list:sim_result = sim_result+ id + ',' +train_dict[id]+ '\n'f_writer.write(sim_result)f_writer.write('**********************************************\n')f_writer.close()if __name__ =="__main__":train_dict =build_dict(GrobalParament.train_set_dir)test_dict = build_dict(GrobalParament.test_set_dir)sim_result_out(GrobalParament.result_out_path,test_dict,train_dict,GrobalParament.sim_result_path)

随机测试几个问题所得到的结果:

1,贪公款被捕后要还钱吗
***最相似的前5个***
1883,贪公款被捕后要还钱吗
3988,借了别人的钱还不起会坐牢吗
1847,贪污公款坐牢还需要还钱吗
1383,借债人突然去世钱还能要回来吗?
3263,碰到无赖亲戚不还钱怎么办
*********************************************
2,贪污公款坐牢还需要还钱吗
***最相似的前5个***
1847,贪污公款坐牢还需要还钱吗
1883,贪公款被捕后要还钱吗
24257,催人还钱,可以用这四大招
6853,捡到的东西多少钱以上构成犯罪
7197,遇离谱“好心人” 捡钱包只还证件不还钱
*********************************************
3,2019欠钱不还能告他吗
***最相似的前5个***
3301,2019欠钱不还能告他吗
44459,2015欠钱不还能告他吗
44728,2015别人欠钱不还怎么办
44643,2015欠钱不还可以报警吗
44658,2015欠钱不还会坐牢吗
*********************************************

小结

这里简单对语料文本进行词向量的训练,并直接通过词序列向量求和取平均作为句子的向量表示,进行句子相似度的计算。这种方式简单粗暴,对于像文章中的短句,而且歧义少的文本有不错的效果。如果目标文本是长文,并且需要考虑词顺序,句子顺序的情况,这种简单的方法很难适应。

更多推荐

NLP文本相似度(word2vec)的原理及实现

本文发布于:2024-03-09 08:40:08,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724494.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文本   原理   NLP   word2vec

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!