本人最近在研究NLP,做了一个简易版的问答系统。
一个问答系统主要包含以下几个模块

  1. 命名实体识别
  2. 句法分析
  3. 实体关系抽取
  4. 知识图谱的构建
  5. 知识推理
  6. 意图识别

今天开个头,以后有时间慢慢写。。。

分词

这边我喜欢用的两个分词包,一个是jieba,另一个是foolnltk
首先看jieba的用法

raw=open(u'../data/昆仑全本.txt',encoding='gb18030',errors='ignore').read()
text=nltk.text.Text(jieba.lcut(raw))#分词

再看foolnltk

fool.analisi(text)[0]

分词技巧
可以结合NER,提高准确率

def segment(txt):#结合NER的分词ner=[i[3] for i in fool.analysis(txt)[1][0]]words=[]for i in ner:txt=txt.replace(i[0],'|||'+i[0]).replace(i[-1],i[-1]+'|||')txt=txt.split('|||')for i in txt:if i in ner:words.append(i)else:for j in fool.analysis(i)[0][0]:words.append(j[0])return words

命名实体识别(NER)

这里主要用foolnltk

text=u'初中老师:到了高中就没人管你们了,作业爱写不写!高中老师:没写完作业的外面的的柜子上补去,这节课不上了什么时候交齐作业再上!真不知道初中老师上没上过高中,但放心高中老师肯定上过初中“这个点初中老师应该讲过”初中同学:写完作业了么,给我发一张                :王者又要新出一个英雄挺厉害的高中同学:记作业了么,给我发一张                 :这TM詹姆斯不是人太NB了初中和高中的差异还是很大的,上了高中就会觉得初中的自己很幼稚,即便是初三和高一的区别。凭借高中老师的大学回忆录我相信大学会更好(高三刚毕业)'
fool.analisi(text)[1]

输出

out:
[[(2, 5, 'job', '老师'),(26, 29, 'job', '老师'),(68, 71, 'job', '老师'),(82, 85, 'job', '老师'),(96, 99, 'job', '老师'),(188, 192, 'person', '詹姆斯'),(245, 248, 'job', '老师'),(262, 266, 'person', '高三刚')]]

句法分析

这一块主要用nltk
用上下文无关法,由下及上
foolnltk可以很方便得查看每个词的词性,所以可以据此构造文法树

def product_grammar(s):#根据词性构造语法l=fool.analysis(s)[0][0]k={}y=[]print(l)for i in l:if i[1] not in y:y.append(i[1])k.update({i[1]:[i[0]]})else:k.update({i[1]:k[i[1]]+[i[0]]})g=''for i,j in k.items():t=i+' ->'c=0for n in j:if len(j)>1 and c<=len(j)-2:t+='\''+n+'\''+'|'else:t+='\''+n+'\''c+=1g+=t+'\n'print('文法:',g)return g

构造出来的文法长这样:

"""S -> NP VPVP -> V NP | V NP PPPP -> P NPV -> "saw" | "ate" | "walked"NP -> "John" | "Mary" | "Bob" | Det N | Det N PPDet -> "a" | "an" | "the" | "my"N -> "man" | "dog" | "cat" | "telescope" | "park"P -> "in" | "on" | "by" | "with""""

构造出完整的文法,就可以分析句子结构了

def draw_1(s):m=sl=fool.cut(s)[0]print(l)p=product_grammar(m)grammar = CFG.fromstring("""S ->NP V NP U L|NP U NP V L| NP U L V NP|L U NP V NP|L V NP U NP|NP V L U NPNP -> N N|r NP|NP A NP|M Q NP|N|NP U NP|A U NP|N NP|NP C NP|NP U|M NPVP ->V|V NP|V VP|A VP|VP NP|VP U|VP C VP|VP P|VP uguoV -> v|vi|vshiN ->n|nr|t|ns|f|nx|nzR ->rC ->cP ->pL ->R|R NPU ->ude|yA ->a|d|adM ->mQ ->q"""+p)cp= nltk.ChartParser(grammar)tree=cp.parse(l)stree=[]for s in tree:st=[]#s.draw()for i in range(len(s)):st.append([s[i].label(),''.join(s[i].leaves())])stree.append(st)return stree

句法依存关系分析与角色标注

这里用pyltp

text='马云和马化腾是好朋友'
par_model_path = os.path.join(LTP_DATA_DIR, 'parser.model')  # 依存句法分析模型路径,模型名称为`parser.model`
from pyltp import Parser
parser = Parser() # 初始化实例
parser.load(par_model_path)  # 加载模型
words = word
postag= [ i for i in postags ]
arcs = parser.parse(words, postag)  # 句法分析rely_id = [arc.head for arc in arcs]    # 提取依存父节点id
relation = [arc.relation for arc in arcs]   # 提取依存关系
heads = ['Root' if id == 0 else words[id-1] for id in rely_id]  # 匹配依存父节点词语
sets={}
for i in range(len(words)):sets[relation[i]]=[ words[i] ,heads[i]]print (relation[i] + '(' + words[i] + ', ' + heads[i] + ')')parser.release()  # 释放模型
set:
SBV(马云, 是)
LAD(和, 马化腾)
COO(马化腾, 马云)
HED(是, Root)
ATT(好, 朋友)
VOB(朋友, 是)

知识推理

知识推理主要用pyDatalog
示例1

pyDatalog.create_terms('X,Y,Z,father,fatherOf,grandfatherOf')
(grandfatherOf[X] == Z) <= ((fatherOf[X]==Y) & (fatherOf[Y]==Z))
fatherOf["乾隆"] = "雍正"
fatherOf["雍正"] = "康熙"
print(grandfatherOf["乾隆"] == X)
out:
X
--
康熙

示例2

pyDatalog.create_terms('X,Y,Z,localed,local')
(local[X] == Z) <= ((localed[X]==Y) & (local[Y]==Z))#关系推导式
localed["马云"] = "香港"
localed["香港"] = "中国"
localed["中国"] = "亚洲"
localed["亚洲"] = "北半球"
print(local["马云"] == X)
out:
X
---
北半球

示例3

from pyDatalog.pyDatalog import load
#load用于加载推理表达式
load("relation(X,'爷爷',Z) <= relation(X,'父亲',Y) & relation(Y,'父亲',Z)")#定义推理表达式load("relation(Y,'孙子',X) <= relation(X,'爷爷',Y)")load("relation(Y,'丈夫',X) <= relation(X,'妻子',Y)")load("relation(Y,'儿子',X) <= relation(X,'父亲',Y)")load("relation(Y,'奶奶',Z) <= relation(Y,'爷爷',X)& relation(X,'配偶',Z)")load("relation(X,'儿媳',Z) <= relation(X,'孙子',Y)& relation(Y,'母亲',Z)")load("relation(X,'亲属',Y) <= relation(X,'孙子',Y)")load("relation(X,'亲属',Y) <= relation(X,'母亲',Y)")load("relation(X,'亲属',Y) <= relation(X,'奶奶',Y)")load("relation(X,'亲属',Y) <= relation(X,'儿子',Y)")load("relation(X,'亲属',Y) <= relation(X,'爷爷',Y)")load("relation(X,'亲属',Y) <= relation(X,'父亲',Y)")load("relation(X,'亲属',Y) <= relation(Y,'亲属',X)")

知识图谱的存储与查询

则利用的数据结构式rdfs
查询语句sparql
python 的rdflib包
用法:
命名空间设置

prefix0 = "http://www.example.org/" # URI的统一前缀
abbr = lambda x: x[len(prefix0):]                  # 取URI的缩写,为了展示的简洁
verbose = lambda x: prefix0+x                      # 恢复缩写为URI的全称

生成一个“图”,并往里面增加知识

g = rdflib.Graph()
def add_data(e1,r,e2,g):r=rdflib.URIRef(verbose(r))e1=rdflib.URIRef(verbose(e1))e2=rdflib.URIRef(verbose(e2))g.add((e1,r,e2))
add_data('马云','在','香港',g)
add_data('香港','在','中国',g)

查询

q = "select ?part where { ?o <http://www.example.org/在> ?part. <http://www.example.org/马云> <http://www.example.org/在> ?part}LIMIT 2"
#相当于问,马云在哪儿?
x = g.query(q)
out:
rdflib.term.URIRef('http://www.example.org/香港')

知识图谱的存储与读取

#存储为Turtle格式
str0 =g.serialize(format='turtle')
open("someFile.ttl","wb").write(str0)#读取
g = rdflib.Graph()
g.parse("someFile.ttl", format="turtle")
for subj, pred, obj in g:          #从RDF取出三元组print(abbr(subj),abbr(pred),abbr(obj))

句子相似度计算

这里有两种方法,一个是编辑距离计算,另一个比较靠谱点的办法是先做词向量(word2vec),然后计算词语余弦值,接着计算句子相似度。
这一块儿有一个很有用的python包gensim

加载别人训练好的词向量

model = KeyedVectors.load_word2vec_format("70000-small.txt")

当然,也可以自己拿一份预料训练词向量,以三国演义这本书为例
定义训练函数

def model_train(train_file_name, save_model_file):  # model_file_name为训练语料的路径,save_model为保存模型名# 模型训练,生成词向量logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)sentences = word2vec.Text8Corpus(train_file_name)  # 加载语料model = gensim.models.Word2Vec(sentences, size=200)  # 训练skip-gram模型; 默认window=5model.save(save_model_file)model.wv.save_word2vec_format(save_model_name + ".bin", binary=True)   # 以二进制类型保存模型以便重用

切词

# 此函数作用是对初始语料进行分词处理后,作为训练模型的语料
def cut_txt(old_file):global cut_file     # 分词之后保存的文件名cut_file = old_file + '_cut.txt'try:fi = open(old_file, 'r', encoding='utf-8')except BaseException as e:  # 因BaseException是所有错误的基类,用它可以获得所有错误类型print(Exception, ":", e)    # 追踪错误详细信息text = fi.read()  # 获取文本内容new_text = jieba.cut(text, cut_all=True)  # 精确模式str_out = ' '.join(new_text).replace(',', '').replace('。', '').replace('?', '').replace('!', '') \.replace('“', '').replace('”', '').replace(':', '').replace('…', '').replace('(', '').replace(')', '') \.replace('—', '').replace('《', '').replace('》', '').replace('、', '').replace('‘', '') \.replace('’', '').replace('的', '').replace('也', '').replace('我们', '')     # 去掉标点符号fo = open(cut_file, 'w', encoding='utf-8')fo.write(str_out)

开始训练

fname='三国演义'
cut_txt(fname+'.txt')  # 须注意文件必须先另存为utf-8编码格式
save_model_name = fname+'.model'
if not os.path.exists(save_model_name):     # 判断文件是否存在model_train(cut_file, save_model_name)
else:print('此训练模型已经存在,不用再次训练')

训练好了就可以加在自己训练的模型了

model_1 = word2vec.Word2Vec.load(save_model_name)

利用已经得到的模型,做词句相似度计算

# 计算某个词的相关词列表
word='笔记本'
y2 = model.most_similar(word, topn=10)  # 10个最相关的
print(u"和"+word+"最相关的词有:\n")
for item in y2:print(item[0], item[1])
print("-------------------------------\n")
out:
和笔记本最相关的词有:笔记本电脑 0.8533223271369934
本本 0.8025031089782715
本子 0.7872854471206665
手提电脑 0.7343267202377319
电脑 0.7327929735183716
台式机 0.7327749133110046
日记本 0.7309284210205078
记事本 0.7292013168334961
笔记 0.696074366569519
平板电脑 0.6858302354812622
-------------------------------

计算句子相似度
定义计算函数

def vector_similarity(s1, s2):def sentence_vector(s):words = jieba.lcut(s)v = np.zeros(200)for word in words:v += model[word]v /= len(words)return vv1, v2 = sentence_vector(s1), sentence_vector(s2)return np.dot(v1, v2) / (norm(v1) * norm(v2))

实验

s1 = '马云的生日是?'
s2 = '马云是95年出生的'
vector_similarity(s1, s2)out:
0.8800125795741638

今天暂时先写到这儿吧,问答系统还包含意图识别等比较复杂的主体,后面有时间再详细些出来,以上内容如对你有用请点赞或收藏,谢谢!

python问答系统实践相关推荐

  1. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part6基于图谱的问答实现

    前序文章: [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视化及问答系统实践:part1项目介绍与环境准备 [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视 ...

  2. 【知识图谱】实践篇——基于医疗知识图谱的问答系统实践(Part2):图谱数据准备与导入

    前序文章: [知识图谱]实践篇--基于医疗知识图谱的问答系统实践(Part1):项目介绍与环境准备 背景 前文已经介绍了该系统的环境准备.下面介绍图谱数据获取,数据主要从:http://jib.xyw ...

  3. python实训总结报告书_20172304 实验四python综合实践报告

    20172304 实验四python综合实践报告 姓名:段志轩 学号:20172304 指导教师:王志强 课程:Python程序设计 实验时间:2020年5月13日至2020年6月14日 实验分析 本 ...

  4. Python机器学习实践指南pdf (中文版带书签)、原书代码、数据集

    Python机器学习实践指南 目 录  第1章Python机器学习的生态系统 1  1.1 数据科学/机器学习的工作  流程 2  1.1.1 获取 2  1.1.2 检查和探索 2  1.1.3 清 ...

  5. 免费教材丨第55期:Python机器学习实践指南、Tensorflow 实战Google深度学习框架

    小编说  时间过的好快啊,小伙伴们是不是都快进入寒假啦?但是学习可不要落下哦!  本期教材  本期为大家发放的教材为:<Python机器学习实践指南>.<Tensorflow 实战G ...

  6. 分享:Python fabric实践操作

    Python fabric实践操作 http://my.oschina.net/guol/blog/97607

  7. python最佳实践笔记

    本文为阅读Python最佳实践指南后的心得体会 结构 README.rst LICENSE setup.py requirements.txt sample/__init__.pycore.pyhel ...

  8. python程序设计实践教程答案-Python程序设计实践教程

    书名:Python程序设计实践教程 定价:29.8 ISBN:9787115532602 作者:储岳中 薛希玲 版次:*1版 出版时间:2020-04 内容提要: 本书是Python语言程序设计的配套 ...

  9. Python自动化实践

    *** Python自动化实践 *** 1.为什么要写代码实现接口自动化 大家知道很多接口测试工具可以实现对接口的测试,如postman.jmeter.fiddler等等,而且使用方便,那么为什么还要 ...

最新文章

  1. layer output 激活函数_一文彻底搞懂BP算法:原理推导+数据演示+项目实战(下篇)...
  2. linux i217 v网卡驱动,手动安装Intel network I217-LM网卡的Linux驱动
  3. 【图解数据结构】二叉查找树
  4. Flutter Mac下环境配置
  5. learn python app v3_‎App Store 上的“Learn Python and Scratch”
  6. FastReport.Net 使用字符串
  7. SpringCloud入门(一)
  8. mysql按照日期先去重在分组_【巨杉数据库Sequoiadb】【咨询】【数据操作】【聚集查询】在执行聚集查询时,字符类型的字段能否按照实际内容进行分组去重...
  9. iOS自定义从底部弹上来的View
  10. Java 接口(interface)的三种类型
  11. 2019通信工程师的职业发展前景和方向
  12. 怎样避免使用手机群控系统被封号的情况
  13. 合格的攻击性白帽黑客应该具备的基本素质(1)
  14. 贝叶斯网络经典matlab源代码解析
  15. Win10休眠后蓝牙键盘无法唤醒怎么办?
  16. Markdown 插入图片 基于base64编码
  17. 误删计算机桌面图标怎么恢复,大神为你解答win7系统恢复误删桌面计算机图标的步骤...
  18. Gitea 无法启动提示 (code=exited, status=203/exec) 错误
  19. 英语初级语法--句子成分(词性)(成分)
  20. Python的enumerate()函数——浅显易懂

热门文章

  1. 解读房产中介的花言巧语
  2. 洛谷P2396 yyy loves Maths VII【状压dp】
  3. 微软免费杀毒软件Morro开始测试 征求定名
  4. 《中台架构与实现》读书笔记
  5. java代码重构原则_重构原则
  6. BUCK电路控制方式
  7. 私厨菜谱app的设计与实现(四)
  8. c语言 变量 section,#pragma DATA_SECTION的解释
  9. section怎么制造图框_Section2014(地质图件制作软件) 4.5.2官方版_增强辅助制图
  10. 人人开心农场制作点滴