基于词向量word2vec匹配的英文问答系统

作者:神秘网友 发布时间:2020-10-01 10:34:35

基于词向量word2vec匹配的英文问答系统

基于词向量word2vec匹配的英文问答系统

环境准备

python3.6
pandas --读取并处理csv文件
nltk --http://www.nltk.org/ 自然语言处理工具包,用于分词,词干提取,语料库
gensim -- 训练word2vec词向量的工具包

实现过程

导入工具包

import pandas as pd 
from nltk.tokenize import word_tokenize
import matplotlib.pyplot as plt #可视化数据集时使用
from gensim.models import Word2Vec
import string
import numpy as np
from queue import PriorityQueue
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()#词形还原,去掉单词词缀,提取单词主干

构建问题词集

对数据库中的所有问题的单词进行提取汇总,构造成含有单词和单词出现次数信息的字典。对各个单词出现的次数进行可视化。
数据集的csv文件如下图所示:
基于词向量word2vec匹配的英文问答系统

data = pd.read_csv('./qanda.csv')
q=data['question']
question_list=q.values.tolist()#以每个问题文本为元素的列表
a=data['answer']
answer_list=a.values.tolist()#以每个答案文本为元素的列表
#构建问题词集 key:单词 value:频数
word_in_q = {}
for x in question_list:
    for x1 in word_tokenize(x.rstrip('?')):#删除?
        if x1 in word_in_q:
            word_in_q[x1] += 1
        else:
            word_in_q[x1] = 1
word_num = sum(word_in_q.values())
word_different = len(word_in_q.keys())

#可视化
dictionary = dict(sorted(word_in_q.items(),key=lambda x:x[1],reverse=True))#按照value的值从大到小排序
x_axis = list(dictionary.keys())
y_axis = list(dictionary.values())
plt.plot(x_axis[:20],y_axis[:20])
plt.show()

文本预处理

文本预处理主要做以下几个部分:
1.去掉问题集的无用词(nltk的停止词语料库)
包括:{‘ourselves’, ‘hers’, ‘between’, ‘yourself’, ‘but’, ‘again’, ‘there’, ‘about’, ‘once’, ‘during’, ‘out’, ‘very’, ‘having’, ‘with’, ‘they’, ‘own’, ‘an’, ‘be’, ‘some’, ‘for’, ‘do’, ‘its’, ‘yours’, ‘such’, ‘into’, ‘of’, ‘most’, ‘itself’, ‘other’, ‘off’, ‘is’, ‘s’, ‘am’, ‘or’, ‘who’, ‘as’, ‘from’, ‘him’, ‘each’, ‘the’, ‘themselves’, ‘until’, ‘below’, ‘are’, ‘we’, ‘these’, ‘your’, ‘his’, ‘through’, ‘don’, ‘nor’, ‘me’, ‘were’, ‘her’, ‘more’, ‘himself’, ‘this’, ‘down’, ‘should’, ‘our’, ‘their’, ‘while’, ‘above’, ‘both’, ‘up’, ‘to’, ‘ours’, ‘had’, ‘she’, ‘all’, ‘no’, ‘when’, ‘at’, ‘any’, ‘before’, ‘them’, ‘same’, ‘and’, ‘been’, ‘have’, ‘in’, ‘will’, ‘on’, ‘does’, ‘yourselves’, ‘then’, ‘that’, ‘because’, ‘what’, ‘over’, ‘why’, ‘so’, ‘can’, ‘did’, ‘not’, ‘now’, ‘under’, ‘he’, ‘you’, ‘herself’, ‘has’, ‘just’, ‘where’, ‘too’, ‘only’, ‘myself’, ‘which’, ‘those’, ‘i’, ‘after’, ‘few’, ‘whom’, ‘t’, ‘being’, ‘if’, ‘theirs’, ‘my’, ‘against’, ‘a’, ‘by’, ‘doing’, ‘it’, ‘how’, ‘further’, ‘was’, ‘here’, ‘than’}
2.全部转为小写
3.去掉低频词(本次未使用)
由于本次实验的问题集很少,因此去掉低频词反而会让结果更加不准确
4.对出现纯数字的情况进行转换
对于纯数字符转成 ‘#number’
5.词干提取(nltk.stem)
忽略每个单词的时态、后缀等变体,我们提取词干的原因是为了缩短查找的时间,使句子正常化。

stopwords = stopwords.words('english')
stopword = ['when','how','what','where','who']
stopwords = [word for word in stopwords if word not in stopword]
#低频词,语料库小的时候不去除
#low_frequency_words = [word for word in word_in_q.keys() if word_in_q[word]<2]
#delete_word = stopwords + low_frequency_words
delete_word = stopwords

def text_processing(question):
    every_question_word = list()
    question = question.lower()#小写
    question = question.strip('?.,!')
    for word in word_tokenize(question):
        word = ''.join(letters for letters in word if letters not in string.punctuation) if word not in string.punctuation else word#去标点
        word = '#number'if word.isdigit() else word#只有数字用
        if word not in delete_word:
            every_question_word.append(lemmatizer.lemmatize(word))#提取每个问句中的单词词干
    return every_question_word

all_question_word = list()#把经过文本预处理的语料库中的问题放入all_quetion_word的list中

训练词向量

model = Word2Vec(all_question_word,min_count=1)

构建单词与单词出现的索引列表构成的字典

统计好每个单词出现在了哪些问题里,有助于接下来根据实际提问筛选出疑似的问题

index_inverted = dict()#构建index_inverted的倒排表,key:单词 value:索引列表
for question in question_list:
    preprocessed_word = text_processing(question)
    all_question_word.append(preprocessed_word)
    for word in preprocessed_word:
        if word not in index_inverted:
            index_inverted.update({word: [question_list.index(question)]})
        else:
            index_inverted[word].append(question_list.index(question))

输入实际提问问题并做预处理

输入实际问题文本之后,通过之前定义的text_processing函数对文本进行预处理,并且将处理后得到的单词列表与index_inverted中的键值单词相对应。得到这些单词对应的疑似数据库问题的索引filter_index。

real_question = "What else is Montreal called?"#可通过语音识别输入
real_question_word = text_processing(real_question)
filter_index = set()
real_question_word_exist = real_question_word[:] #复制列表
# 这里筛去了问题集中没有但是实际提问中出现的单词,便于后续计算余弦相似度
for word in real_question_word:   
    if word not in index_inverted.keys():
        real_question_word_exist.remove(word)
    else:
        filter_index.update(index_inverted[word])

求词向量余弦距离得到匹配的问题及对应答案

#过滤出疑似问题
part_question_word = list()
for index in filter_index:#过滤出疑似问题
    one_question_word = all_question_word[index]
    part_question_word.append(one_question_word)
siml_list = list()
for question_word in part_question_word:
    siml=model.n_similarity(real_question_word_exist,question_word)#计算集合之间的余弦相似度
    siml_list.append(siml)
if max(siml_list)>0.9:#存在相似度大于0.9的问题才给出对应回答
    top_question = PriorityQueue()#优先队列
    for i in range(len(siml_list)):
        top_question.put((siml_list[i],part_question_word[i]))#
        if len(top_question.queue) > 5:#每次top_question.queue超过5个时就踢走最大的元素 和 值
            top_question.get()#得到最大的5个元素和值(未排序)
    top_question = top_question.queue
    print(top_question)
    sorted_top_question = sorted(top_question, key=lambda t: t[0], reverse=True)
    print('sorted_top_question\n',sorted_top_question)#打印出相似度前5的问题

    answers = [answer_list[all_question_word.index(question[1])] for question in sorted_top_question]
    print('answers\n',answers) #打印出问题对应的答案
else:#提问不在问题集的范围内,另做处理
    print("This question not exist in my lib!")

最终输出结果

sorted_top_question
 [(1.0, ['what', 'else', 'montreal', 'called']), (0.43783137, ['what', 'mechanical', 'knight']), (0.3780565, ['what', 'origin', 'comic', 'sans', 'font']), (0.32334372, ['what', 'moravec', 'paradox', 'state']), (0.32260603, ['what', 'nanobot'])]
answers
 ['Montreal is often called the City of Saints or the City of a Hundred Bell Towers.', 'A robot sketch made by Leonardo DaVinci.', "Comic Sans is based on Dave Gibbons' lettering in the Watchmen comic books.", "Moravec's paradox states that a computer can crunch numbers like Bernoulli, but lacks a toddler's motor skills.", 'The smallest robot possible is called a nanobot. ']

总结

这是一个很简单的根据词向量相似度匹配的问答系统,对于给定问答集的情况可以使用。效果好于使用预训练的glove.6B词向量。
需要改进的地方:
对实际问题的文本处理需要剔除问题集中没有的词汇,这对于替换近义词提问难以得到正确答案。
……

参考链接

NLTK最详细功能介绍
简易英文问答系统(glove.6B词向量)

基于词向量word2vec匹配的英文问答系统相关教程

  1. SpringMVC之基于注解的数据校验

    SpringMVC之基于注解的数据校验 文章目录 前言 一、为什么使用后端数据校验? 二、使用步骤 1.引包 2.打上对应的注解 3.在controller层对应方法的参数上打上注解 4.判断是否成功校验 5.表单回显 前言 越学越能体会spring框架的精妙 , 基于注解的设计真是太优雅

  2. 基于 Keras 和 Tensorflow 的标签平滑实现

    基于 Keras 和 Tensorflow 的标签平滑实现 首先谢谢原文作者写出这么好的文章,帮助像我这样的初学者能快速的了解并应用相关技术,谢谢!!! 首先附上原文地址 :基于 Keras 和 Tensorflow 的标签平滑实现. 目录 1.标签平滑出现的意义和背景 2.标签平滑以及其

  3. 西门子PLC-1200的基于232串口的Modbus RTU通讯实例

    西门子PLC-1200的基于232串口的Modbus RTU通讯实例 西门子PLC-1200的基于232串口的Modbus RTU通讯实例 这里先讲一下Modbus和232,232和485串口是一种串口接法,这种接法实际能实现十几种的协议通讯,有基于串口的Modbus RTU,Modbus+,有基于以太网接口的Modbus

  4. (转)基于TLS证书手动部署kubernetes集群(上)

    (转)基于TLS证书手动部署kubernetes集群(上) 转:https://www.cnblogs.com/wdliu/archive/2018/06/06/9147346.html 一、简介 Kubernetes是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,Kubernetes也叫K8S。 K8S是Google内部一个叫Borg的

  5. 基于Javaweb的学生宿舍管理系统(源码+数据库+报告)

    基于Javaweb的学生宿舍管理系统(源码+数据库+报告) 1、 系统开发目标及设计思想 1.1 系统开发基本目标 学生宿舍管理系统的开发主要是为了解决学生住宿及其相关问题,同时满足管理者方便管理的需求。随着各个高校不断扩招,与住宿的同学数量的增多,各种住宿

  6. 基于H.ui.Admin UI模板的网站管理后台

    基于H.ui.Admin UI模板的网站管理后台 最近接手一个跨境电商平台开发,客户侧重电商网站UI设计,对管理后台要求不高,由我们决定选哪一款后台模板。找来找去,感觉还是H.ui靠谱一些,主要是这个模板清爽,不需要过多选择。其他的流行后台模板也看了,但功能

  7. javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式

    javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据。 Servlet+JSP+JavaBean模式程序各个模

  8. 基于深度学习的推荐(四):阿里DIN,使用Attention获得用户的动态

    基于深度学习的推荐(四):阿里DIN,使用Attention获得用户的动态representation 文章目录 公众号 前言 1.模型分析 1.1 Baseline 1.2 DIN 2. 训练技巧 2.1 Dice激活函数 2.2 Mini-batch 正则化 3.实战 3.1 数据集 3.2 代码分析 参考 关注公众号: 推荐算法工程