现在的智能问答系统的应用是非常普遍的,比如说客服,前台机器人,讲解机器人等很多场景都可能会用到FAQ问答系统,所谓的FAQ就是 frequently asked questions,也就是说在某个场景下,比较常见的一些问题。
首先我们来看看整体的FAQ流程,我们需要对输入的问题进行预处理,比如去停,分词等;然后需要对预处理之后的语料进行向量化,这里向量化的方法很多,也不拘泥于一种,常见的向量化方法有词频向量化、word2vec、tf-idf 等方法;向量化之后,就可以进行文本相似度计算了然后我们可以选取相似度最高的问题答案输出就可以了。
整个处理的流程图如下所示:
好了,明白了整个流程了之后,我们就可以开始搭建问答系统了。首先,是创建问答库,这里我们就创建一个十来个问题的问题库和答案库,顺序要一一对应起来:
问题库:
答案库:
好了,问答库弄好了之后,我们要对问题库进行预处理操作,主要就是进行分词操作,代码如下所示:
import jieba
def stopword_list():
stopwords = [line.strip() for line in open('stopword.txt', encoding='utf-8').readlines()]
return stopwords
def seg_with_stop(sentence):
sentence_seg = jieba.cut(sentence.strip())
stopwords = stopword_list()
out_string = ''
for word in sentence_seg:
if word not in stopwords:
if word != '\t':
out_string += word
out_string += " "
return out_string
def segmentation(sentence):
sentence_seg = jieba.cut(sentence.strip())
out_string = ''
for word in sentence_seg:
out_string += word
out_string += " "
return out_string
inputQ = open('Question.txt', 'r', encoding='gbk')
outputQ = open('QuestionSeg.txt', 'w', encoding='gbk')
inputA = open('Answer.txt', 'r', encoding='gbk')
outputA = open('AnswerSeg.txt', 'w', encoding='gbk')
for line in inputQ:
line_seg = segmentation(line)
outputQ.write(line_seg + '\n')
outputQ.close()
inputQ.close()
for line in inputA:
line_seg = segmentation(line)
outputA.write(line_seg + '\n')
outputA.close()
inputA.close()
我们逐行对问题库进行了分词操作,然后输出。接下来我们就可以进行输入问题 query 进行向量化,然后和问题库中的问题向量进行相似度计算,这里我们用的是余弦相似度算法,然后取相似度最高的问题相对应的答案输出即可,其实流程是比较简单的。代码如下所示:
from sklearn.feature_extraction.text import CountVectorizer
import math
from segmentation import segmentation
count_vec = CountVectorizer()
def count_cos_similarity(vec_1, vec_2):
if len(vec_1) != len(vec_2):
return 0
s = sum(vec_1[i] * vec_2[i] for i in range(len(vec_2)))
den1 = math.sqrt(sum([pow(number, 2) for number in vec_1]))
den2 = math.sqrt(sum([pow(number, 2) for number in vec_2]))
return s / (den1 * den2)
def cos_sim(sentence1, sentence2):
sentences = [sentence1, sentence2]
# print(count_vec.fit_transform(sentences).toarray()) # 输出特征向量化后的表示
# print(count_vec.get_feature_names()) # 输出的是切分的词, 输出向量各个维度的特征含义
vec_1 = count_vec.fit_transform(sentences).toarray()[0]
vec_2 = count_vec.fit_transform(sentences).toarray()[1]
# print(len(vec_1), len(vec_2))
return count_cos_similarity(vec_1, vec_2)
def get_answer(sentence1):
sentence1 = segmentation(sentence1)
score = []
for idx, sentence2 in enumerate(open('QuestionSeg.txt', 'r')):
# print('idx: {}, sentence2: {}'.format(idx, sentence2))
# print('idx: {}, cos_sim: {}'.format(idx, cos_sim(sentence1, sentence2)))
score.append(cos_sim(sentence1, sentence2))
if len(set(score)) == 1:
print('暂时无法找到您想要的答案。')
else:
index = score.index(max(score))
file = open('Answer.txt', 'r').readlines()
print(file[index])
while True:
sentence1 = input('请输入您需要问的问题(输入q退出):\n')
if sentence1 == 'q':
break
else:
get_answer(sentence1)
好了,我们可以试试效果如何:
仅仅通过余弦相似度匹配,我们就可以有一个不错的效果了,这就是一个简单的问答系统搭建。希望能让大家对QA系统有一个初步的了解,如有纰漏之处,也请大家不吝指教,代码详情请见 GitHub,谢谢。