1 什么是pyltp
语言技术平台(LTP) 是由 哈工大社会计算与信息检索研究中心 11
年的持续研发而形成的一个自然语言处理工具库,其提供包括中文分词、词性标注、命名实体识别、依存句法分析、语义角色标注等丰富、
高效、精准的自然语言处理技术。LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic
Link Library, DLL)的应用程序接口,可视化工具,并且能够以网络服务(Web Service)的形式进行使用。
默认上来说,ltp平台是基于C++的,但是大家也都知道我是不用C++的,所以我看到了其Python的版本,pyltp,于是拿来写了个手札。
我目前主要用到的部分可能还是以中文分词为主,其他后续加上(PS:因为我觉得之前那个不太喜欢)。
NLPIR 汉语分词系统 (PyNLPIR) 学习手札
好了废话不多说,一步一步来,让我们先从安装开始。
这次我首次安装pyltp的平台是windows 10(我的环境osx or windows10 or Ubuntu,一般nlp相关的都是osx或win上,平台相关的都是Ubuntu) + python2.7
1 pyltp 安装
1、使用Pip进行安装
关于Pip,已经不用重复太多了,快速简单,我也一直用,这里也一样。
$ pip install pyltp
这里说一下我遇到的问题,缺少Visual C++ 9.0:
Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat). Get it from http://aka.ms/vcpython27
解决方式(2选1):
1、安装一个Visual Studio 2008 只能是这个版本,网上说12,我的15都不行
2、安装一个Micorsoft Visual C++ Compiler for Python 2.7,或者这个链接直接下载,但是可能会失效 安装完成后,重新运行那个安装指令就可以了
2、模型下载
安装完成后,我们需要安装pyltp的模型,从百度云这里下载 ,注意模型版本必须要和pynlp的版本对应
我写文的时候,使用的是3.3.1,注意网盘里面有个zip和tar两种,选择一个你能下载的就可以了
pyltp 版本:0.1.9 LTP 版本:3.3.2 模型版本:3.3.1
3 配置
当我们完成了安装和模型下载后,就需要做一些相关的配置,保证pyltk可以使用到对应的模型
这里所谓的配置,就是在代码中,需要预先load一下
1、将上述的模型压缩包解压到指定的文件夹
2、在使用时,使用类似的方式的加载模型,注意替换自己的模型地址
segmentor.load('/path/to/your/model')
3 pyltk 使用
分句
分句,也就是将一片文本分割为独立的句子,不需要加载模型的哦,我看了一下应该就是按照符号来分割的。
from pyltp import SentenceSplitter
def sentence_splitter(sentence='你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。'):
sents = SentenceSplitter.split(sentence)
print '\n'.join(sents)
sentence_splitter()
运行结果
分词
关于分词是什么,就不用多说了,直接看。
注意分词的模型默认是:cws.model
from pyltp import Segmentor
def segmentor(sentence='你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。我的微博是MebiuW,转载请注明来自MebiuW!'):
segmentor = Segmentor()
segmentor.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\cws.model')
words = segmentor.segment(sentence)
words_list = list(words)
for word in words_list:
print word
segmentor.release()
return words_list
segmentor()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
运行结果
分词-高级
注意此部分,我是直接复制了官方文档
以下代码中的XX模型,请自定替换为模型的地址!!!
pyltp 分词支持用户使用自定义词典。分词外部词典本身是一个文本文件(plain text),每行指定一个词,编码同样须为 UTF-8,样例如下所示
苯并芘
亚硝酸盐
示例如下
# -*- coding: utf-8 -*-
from pyltp import Segmentor
segmentor = Segmentor() # 初始化实例
segmentor.load_with_lexicon(
words = segmentor.segment(
print
segmentor.release()
使用个性化分词模型
个性化分词是 LTP 的特色功能。个性化分词为了解决测试数据切换到如小说、财经等不同于新闻领域的领域。 在切换到新领域时,用户只需要标注少量数据。 个性化分词会在原有新闻数据基础之上进行增量训练。 从而达到即利用新闻领域的丰富数据,又兼顾目标领域特殊性的目的。
pyltp 支持使用用户训练好的个性化模型。关于个性化模型的训练需使用 LTP,详细介绍和训练方法请参考 个性化分词 。
在 pyltp 中使用个性化分词模型的示例如下
from pyltp import CustomizedSegmentor
customized_segmentor = CustomizedSegmentor()
customized_segmentor.load('基本模型', '个性模型')
words = customized_segmentor.segment('亚硝酸盐是一种化学物质')
print '\t'.join(words)
customized_segmentor.release()
同时使用外部字典的话
from pyltp import CustomizedSegmentor
customized_segmentor = CustomizedSegmentor()
customized_segmentor.load_with_lexicon('基本模型', '个性模型', '用户字典')
words = customized_segmentor.segment('亚硝酸盐是一种化学物质')
print '\t'.join(words)
customized_segmentor.release()
#词性标注
词性标注也是我们经常遇到的任务,也不多解释了
词性标注需要输入分词后的结果,所以请先参考下之前的按个分词部分,其返回的结果可以作为输入直接标注
from pyltp import Segmentor
from pyltp import Postagger
def segmentor(sentence='你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。我的微博是MebiuW,转载请注明来自MebiuW!'):
segmentor = Segmentor()
segmentor.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\cws.model')
words = segmentor.segment(sentence)
words_list = list(words)
segmentor.release()
return words_list
def posttagger(words=segmentor()):
postagger = Postagger()
postagger.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\pos.model')
postags = postagger.postag(words)
for word,tag in zip(words,postags):
print word+'/'+tag
postagger.release()
posttagger()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
运行结果: 前面是词语,后面是词性,词性的表述请参照这里
命名实体识别
命名实体识别,主要是hi识别一些人名,地名,机构名等。
需要前面分词和词性标注作为输入
from pyltp import NamedEntityRecognizer
def ner(words, postags):
recognizer = NamedEntityRecognizer()
recognizer.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\ner.model')
netags = recognizer.recognize(words, postags)
for word, ntag in zip(words, netags):
print word + '/' + ntag
recognizer.release()
return netags
words = segmentor('我家在昆明,我现在在北京上学。中秋节你是否会想到李白?')
tags = posttagger(words)
ner(words,tags)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
运行结果
命名实体的参照标记,也是请看这里
依存句法分析
依存句法依旧需要之前的两个输入,words 和 postags 分别为分词和词性标注的结果。
arc.head 表示依存弧的父节点词的索引,arc.relation 表示依存弧的关系。其具体的表述看这里
from pyltp import Parser
def parse(words, postags):
parser = Parser()
parser.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\parser.model')
arcs = parser.parse(words, postags)
print "\t".join("%d:%s" % (arc.head, arc.relation) for arc in arcs)
parser.release()
words = segmentor('我家在昆明,我现在在北京上学。中秋节你是否会想到李白?还有,微博是MebiuW')
tags = posttagger(words)
parse(words,tags)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
运行结果
语义角色标注
arg.name 表示语义角色关系,arg.range.start 表示起始词位置,arg.range.end 表示结束位置。
from pyltp import SementicRoleLabeller
def role_label(words, postags, netags, arcs):
labeller = SementicRoleLabeller()
labeller.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\srl')
roles = labeller.label(words, postags, netags, arcs)
for role in roles:
print role.index, "".join(
["%s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments])
labeller.release()
words = segmentor('我家在昆明,我现在在北京上学。中秋节你是否会想到李白?还有,微博是MebiuW')
tags = posttagger(words)
netags = ner(words,tags)
arcs = parse(words,tags)
roles = role_label(words,tags,netags,arcs)
运行结果:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
角色对照看这里
结语
有点累,突然写不动了,就先写这些吧,有问题我们评论或者新浪微博@MebiuW 交流
参考
1、Pyltk 官方文档
参考本篇完整代码
可能有些打印有点杂乱,见谅
from pyltp import SentenceSplitter
from pyltp import Segmentor
from pyltp import Postagger
from pyltp import SementicRoleLabeller
from pyltp import NamedEntityRecognizer
from pyltp import Parser
def segmentor(sentence='你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。我的微博是MebiuW,转载请注明来自MebiuW!'):
segmentor = Segmentor()
segmentor.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\cws.model')
words = segmentor.segment(sentence)
print '\t'.join(words)
words_list = list(words)
segmentor.release()
return words_list
def posttagger(words):
postagger = Postagger()
postagger.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\pos.model')
postags = postagger.postag(words)
for word,tag in zip(words,postags):
print word+'/'+tag
postagger.release()
return postags
def sentence_splitter(sentence='你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。我的微博是MebiuW,转载请注明来自MebiuW!'):
sents = SentenceSplitter.split(sentence)
print '\n'.join(sents)
def ner(words, postags):
recognizer = NamedEntityRecognizer()
recognizer.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\ner.model')
netags = recognizer.recognize(words, postags)
for word, ntag in zip(words, netags):
print word + '/' + ntag
recognizer.release()
return netags
def parse(words, postags):
parser = Parser()
parser.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\parser.model')
arcs = parser.parse(words, postags)
print "\t".join("%d:%s" % (arc.head, arc.relation) for arc in arcs)
parser.release()
return arcs
def role_label(words, postags, netags, arcs):
labeller = SementicRoleLabeller()
labeller.load('C:\\Users\\72770\\Documents\\Chatbot\\ltp-data-v3.3.1\\ltp_data\\srl')
roles = labeller.label(words, postags, netags, arcs)
for role in roles:
print role.index, "".join(
["%s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments])
labeller.release()
print('******************测试将会顺序执行:**********************')
sentence_splitter()
print('###############以上为分句子测试###############')
words = segmentor('我家在昆明,我现在在北京上学。中秋节你是否会想到李白?还有,微博是MebiuW')
print('###############以上为分词测试###############')
tags = posttagger(words)
print('###############以上为词性标注测试###############')
netags = ner(words,tags)
print('###############以上为命名实体识别测试###############')
arcs = parse(words,tags)
print('###############以上为依存句法测试###############')
roles = role_label(words,tags,netags,arcs)
print('###############以上为角色标注测试###############')