基于知识库与知识图谱构建电影问答系统

在上一篇文章 基于豆瓣电影数据构建知识图谱 里面,讲到如何采用Neo4j来构建电影图谱,并且掌握了Neo4j里面的初级查询功能(搜索实体属性、实体间的关系等)。接下来,将进入电影图谱问答系统的学习,通过知识库和知识图谱来构建电影问答系统。针对QA问答系统,由于笔者当前能力有限,本文仅介绍基于模板的知识库问答,讲解过程中如果有阐述不周之处,还请读者指出!下面,我们来看看如何对问题进行解析,并将图谱应用到电影问答系统。

往期回顾:

Introduction

本文的电影QA问答系统工作流程如Fig 1所示,当接受到一个问题之后,我们首先对问题进行解析,包括分词、词性标注、关键字提取等预处理操作,并根据训练好的分类模型对问题进行分类,得到问题所属类之后,再根据图谱知识库搜索答案。在整个工作流程中,知识库在上一篇文章已经构建好了,并且已经存储到neo4j中。本文的主要工作是从问题到答案,端到端的实现。重点在如何对问题进行解析和分类,其次是借助neo4j进行答案检索。

Fig 1.QA问答系统工作流程

问题解析

当用户提出一个问题:”张国荣演过哪些电影?”时,我们需要对文本数据进行处理。在这里可以采用jieba进行分词、词性标注等操作,然后提取关键字。比如上面的问句,通过jieba进行词性标注的结果会是什么样子的呢?结果如下:

['张国荣/nr', '演/v', '过/ug', '哪些/r', '电影/n']

我们看到“张国荣”被标记为nr,属于人名,演是动词,后面还有一些其他的,得到这个结果之后,接下来该怎么处理呢?我们再看看Fig 1,当问题解析完之后,我们需要对问题进行分类。说到分类,就必须得有个训练模型才行!下面就是一个问题多分类模型。基于问题模板数据来训练问题分类模型。

基于NB的问题分类模型

在这个章节中,我们将采用简单的NB算法来训练我们的分类模型,感兴趣的童鞋可以试试其他的分类算法。

数据集

首先,来说说我们的数据集,样例数据如下,数据集包括三列,第一列是label(多分类),第二列是text(问题模板文本),第三列是描述(可忽略)。由于是实验demo,数据样例比较少,后续会根据需求不断扩展。

Fig 2.问题分类数据集样例

对于上面的数据集,可能有的童鞋会有点问题,nm表示什么?这里简单说一下,nm表示的电影的词性标注。在问题解析阶段,会对jieba的分词注入用户个人字典,每个电影的词性标注均为nm。这样,在分词之后,得到的结果也是nm。

例如:“红海行动讲的是什么故事?”,解析后的词与词性如下:

['红海行动/nm', '讲/v', '的/uj', '是/v', '什么/r', '故事/n']

模型训练

关于模型部分,,其中用到了sklearn、pandas、jieba库,完整的代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 24 14:38:04 2019

@author: liudiwei
"""
import jieba
import pandas as pd
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfVectorizer
jieba.load_userdict("./data/userdict3.txt")

class QuestionPrediction():
    """
    问题预测: 采用NB进行多分类
    数据集:template_train.csv
    """
    def __init__(self):
        # 训练模板数据
        self.train_file = "./data/template_train.csv"
        # 读取训练数据
        self.train_x, self.train_y=self.read_train_data(self.train_file)
        # 训练模型
        self.model=self.train_model_NB()

    # 获取训练数据
    def read_train_data(self,template_train_file):
        """
        可改写为读取一个文件
        """
        train_x=[]
        train_y=[]
        train_data = pd.read_csv(template_train_file)
        train_x = train_data["text"].apply(lambda x: " ".join(list(jieba.cut(str(x))))).tolist()
        train_y = train_data["label"].tolist()
        return train_x,train_y

    def train_model_NB(self):
        """
        采用NB训练模板数据,用于问题分类到某个模板
        """
        X_train, y_train = self.train_x, self.train_y
        self.tv = TfidfVectorizer()

        train_data = self.tv.fit_transform(X_train).toarray()
        clf = MultinomialNB(alpha=0.01)
        clf.fit(train_data, y_train)
        return clf

    
    def predict(self,question):
        """
        问题预测,返回结果为label
        """
        question=[" ".join(list(jieba.cut(question)))]
        print("question:", question)
        test_data=self.tv.transform(question).toarray()
        y_pred = self.model.predict(test_data)[0]
        return y_pred

if __name__ == '__main__':
    question_model=QuestionPrediction()
    print(question_model.predict("红海行动讲的是什么故事?"))

通过 read_train_data 方法,我们得到的分词后的 x_train 如Fig 3的value字段所示。

Fig 3.训练数据样例

预测

单独执行上面的代码,最后返回的结果如Fig 4所示。最终将”红海行动讲的是什么故事?”划分到第三个类别。

Fig 4.问题预测结果

基于图谱的搜索

通过预测模型,我们可以将问题划分到某个模板中,接下来,再基于问题模板构造图谱搜索,比如上面的问题,我们将其划分到第三类问题:电影简介。接下来就可以采用py2neo连接neo4j图数据库,然后从图数据库中搜索出想要的答案。

# 3:nm 电影简介
def get_movie_introduction(self):
    movie_name = self.get_movie_name()
    cql = f"match(m:Movie)-[]->() where m.title=~'.*{movie_name}.*' return m.storyline"
    print(cql)
    answer = self.graph.run(cql)[0]
    final_answer = movie_name + "主要讲述了" + str(answer) + "!"
    return final_answer

最后得到的结果如下:

Fig 5.问题预测结果

Conclusion

本文主要讲解了如何端到端的构建QA系统,方法虽然比较简单,但可以让读者了解整个工作流,对后续的学习也会有很好的帮助。为了将结果更好的展示出来,笔者将QA问答做成了服务,部署到了服务器中,并在服务器中搭建neo4j,构建电影图谱,最后将QA问答与微信公众号进行了集成,结果如Fig 6所示。由于问答模板不够完善,公众号暂时就不公布了。文中代码仅供参考,具体的源码等整理完之后再发布到github中吧。关于如何发布QA服务和微信公众号自动问答的集成,我们下期再见!

Fig 6.电影QA集成微信公众号

References

  1. 豆瓣13万电影数据统计与分析
  2. 基于豆瓣电影数据构建知识图谱
  3. Knowledge Graph - Wikipedia
  4. Importing CSV Data into Neo4j
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章