聊天机器人(chatterbot)是一个用来模拟人类对话或聊天的程序。“Eliza”和 “Parry”是早期非常著名的聊天机器人。它试图建立这样的程序:至少暂时性地让一个真正的人类认为他们正在和另一个人聊天。
聊天机器人是怎么工作的?
大致上有两种类型的聊天机器人: 基于规则的和自学习的。
1. 基于规则的:根据训练的规则哎回答问题。定义的规则可以非常简单,也可以非常复杂。机器人可以处理简单的查询,但不能处理复杂的查询。
2. 自学习机器人:使用一些基于机器学习的方法,它比基于规则的机器人更有效率。这些机器人还可以有两种类型:基于检索或生成性
(一)基于检索:聊天机器人使用一些启发式方法从预定义响应库中选择响应。Chatbot使用会话的消息和上下文从预定义的bot消息列表中选择最佳响应。上下文可以包括对话框树中的当前位置、会话中的所有先前消息、先前保存的变量(例如用户名)。选择响应的启发式方法可以通过多种不同的方式进行,从基于规则的if-否则条件逻辑到机器学习分类器。
(二)生成性机器人可以生成答案,而不是总是从一组答案中生成一个答案。这使得他们更聪明,因为他们从查询中逐字逐句地获取并生成答案。
今天就来开发一个基于检索的聊天机器人系统。我们的系统要实现一个针对特定问题进行应答的功能,我们的数据来自于百度百科关于5G网络描述的网页,我们的机器人将回答您的关于5G网络的相关问题。
数据
我们首先打开百度百科关于5G网络描述的网页,然后将该网页中的内容拷贝至一个文本文件中,并稍微整理一下:
数据预处理
我们先加载所需要的库,我们将会用到jieba分词工具和sklearn等nlp和机器学习所需要的库。
import codecs
import jieba as jb
import re
import warnings
warnings.filterwarnings("ignore")
import pandas as pd
import random
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
接下来我们先定义几个处理中文字符的函数,其中包括中文分句,删除标点符号,加载停用词等函数。
#中文分局
def SentsTokenizer4Ch(text):
sentences = re.split('(。|!|\!|?|\?)',text)
new_sents = []
for i in range(int(len(sentences)/2)):
sent = sentences[2*i] + sentences[2*i+1]
sent = sent.replace('\r\n','')
sent = sent.strip()
new_sents.append(sent)
return new_sents
#删除所有符号,只保留字母、数字和中文
def remove_punctuation(line):
#line = str(line)
if line.strip()=='':
return ''
rule = re.compile(u"[^a-zA-Z0-9\u4E00-\u9FA5]")
line = rule.sub('',line)
return line
#中文停用词
def stopwordslist(filepath):
stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
return stopwords
#加载停用词
stopwords = stopwordslist("./data/chineseStopWords.txt")
定义好这些函数以后,我们就可以加载我们的数据了,我们先加载这篇文章,然后把文章中的所有句子都分离出来(分句)
myfile = "./data/chatbot-data/5G-ch.txt"
text = codecs.open(myfile, "r", "utf-8").read()
sent_tokens = SentsTokenizer4Ch(text)
sent_tokens[:10]
分句工作完成好以后,接下来我们就要开始对这些句子进行处理,这其中包括删除句子中的各自符号,删除停用词,并进行分句。
#删除除字母,数字,汉字以外的所有符号
df = pd.DataFrame(sent_tokens, columns=['sent'])
df['clean_set']= df['sent'].apply(remove_punctuation)
#分词,并过滤停用词
# df['cut_sent'] = df['clean_set'].apply(lambda x: " ".join([w for w in list(jb.cut(x)) if w not in stopwords]))
df['cut_sent'] = df['clean_set'].apply(lambda x: " ".join([w for w in list(jb.cut(x))]))
df.head()
问答设计
问候语设计
当用户和机器人初次见面的时候,我们预先定义一些双方的问候语:
GREETING_INPUTS = ("你好", "hi", "有人", "在吗", "嗨","在不在","有人吗",'在','有人')
GREETING_RESPONSES = ["你好", "我在", "请问,有什么可以帮您的吗?", "你好,我在", "你好,很高兴见到你!"]
def greeting(sentence):
rule = re.compile(u"[^a-zA-Z0-9\u4E00-\u9FA5]")
text = rule.sub('',sentence)
if text in GREETING_INPUTS:
return random.choice(GREETING_RESPONSES)
wordlist = [w for w in jieba.cut(sentence)]
for word in wordlist:
if word in GREETING_INPUTS:
return random.choice(GREETING_RESPONSES)
机器应答设计
机器应答是本系统的核心模块,我们要设计一个针对用户问题的应答函数。应答的过程是这样的,当用户提出关于5G网络的问题后,系统会将用户的问题先做格式化处理(如分词,删除标点符号,删除停用词等),然后在现有的数据中通过余弦相似度去匹配一条与用户的问题最相似的句子,并将该句子输出给用户。
def response(user_response):
robo_response=''
user_response = remove_punctuation(user_response)
user_response= " ".join([w for w in list(jb.cut(user_response)) if w not in stopwords])
cut_sent = df.cut_sent.values.tolist()
cut_sent.append(user_response)
tfidf = TfidfVectorizer()
tfidf_vec = tfidf.fit_transform(cut_sent)
cos_sim = cosine_similarity(tfidf_vec[-1], tfidf_vec)
idx=cos_sim.argsort()[0][-2]
flat = cos_sim.flatten()
flat.sort()
req_tfidf = flat[-2]
if(req_tfidf==0):
robo_response=robo_response+"对不起,我不理解您的意思,我还是个小白...!"
return(robo_response)
else:
robo_response = robo_response+df.sent.values[idx]
return(robo_response)
流程设计
好了,万事俱备只欠东风,我们要开始设计一个机器人聊天系统的工作流程,首先机器人应该先自我介绍同时告诉用户退出系统的方法,然后等待用户输入问题,用户输入问题后,我们会在系统中搜索与用户问题最相似的句子,并将该句子返回给用户,然后继续等待用户输入下一个问题。直到用户最后输入“bye”,则退出系统。
flag=True
print("机器人: 我的名字叫小白. 我可以回答您关于5G的问题. 如果您想退出, 请输入:bye !")
while(flag==True):
user_response = input()
user_response=user_response.lower()
if(user_response!='bye'):
if(user_response=='多谢' or user_response=='谢谢' ):
flag=False
print("机器人: 不用谢!")
else:
if(greeting(user_response)!=None):
print("机器人: "+greeting(user_response))
print()
else:
print("机器人: ",end="")
print(response(user_response))
print()
else:
flag=False
print("小白: 再见! 欢迎再次光临!")
效果
总结
今天我给大家演示了一个基于检索的简单聊天机器人系统,该系统是基于余弦相似度进行相似语句的匹配。程序中还有很多不完善的地方,有心的读者可以想办法对它进行改进,并希望能分享给我,让我们大家一起进步吧!