首页 > 代码库 > Python下的自然语言处理利器-LTP语言技术平台 pyltp 学习手札

Python下的自然语言处理利器-LTP语言技术平台 pyltp 学习手札

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 使用

分句

分句,也就是将一片文本分割为独立的句子,不需要加载模型的哦,我看了一下应该就是按照符号来分割的。

# -*- coding: utf-8 -*-
from pyltp import SentenceSplitter
#分句,也就是将一片文本分割为独立的句子
def sentence_splitter(sentence=‘你好,你觉得这个例子从哪里来的?当然还是直接复制官方文档,然后改了下这里得到的。‘):
    sents = SentenceSplitter.split(sentence)  # 分句
    print ‘\n‘.join(sents)

#测试分句子
sentence_splitter()

运行结果
技术分享

分词

关于分词是什么,就不用多说了,直接看。
注意分词的模型默认是:cws.model

# -*- coding: utf-8 -*-
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)  # 分词
    #默认可以这样输出
    # print ‘\t‘.join(words)
    # 可以转换成List 输出
    words_list = list(words)
    for word in words_list:
        print word
    segmentor.release()  # 释放模型
    return words_list
#测试分词
segmentor()

运行结果
技术分享

分词-高级

注意此部分,我是直接复制了官方文档

以下代码中的XX模型,请自定替换为模型的地址!!!

pyltp 分词支持用户使用自定义词典。分词外部词典本身是一个文本文件(plain text),每行指定一个词,编码同样须为 UTF-8,样例如下所示

苯并芘
亚硝酸盐

示例如下

# -*- coding: utf-8 -*-
from pyltp import Segmentor
segmentor = Segmentor()  # 初始化实例
segmentor.load_with_lexicon(‘模型地址, ‘用户字典‘) # 加载模型
words = segmentor.segment(‘亚硝酸盐是一种化学物质‘)
print ‘\t‘.join(words)
segmentor.release()

使用个性化分词模型
个性化分词是 LTP 的特色功能。个性化分词为了解决测试数据切换到如小说、财经等不同于新闻领域的领域。 在切换到新领域时,用户只需要标注少量数据。 个性化分词会在原有新闻数据基础之上进行增量训练。 从而达到即利用新闻领域的丰富数据,又兼顾目标领域特殊性的目的。
pyltp 支持使用用户训练好的个性化模型。关于个性化模型的训练需使用 LTP,详细介绍和训练方法请参考 个性化分词 。
在 pyltp 中使用个性化分词模型的示例如下

# -*- coding: utf-8 -*-
from pyltp import CustomizedSegmentor
customized_segmentor = CustomizedSegmentor()  # 初始化实例
customized_segmentor.load(‘基本模型‘, ‘个性模型‘) # 加载模型
words = customized_segmentor.segment(‘亚硝酸盐是一种化学物质‘)
print ‘\t‘.join(words)
customized_segmentor.release()

同时使用外部字典的话

# -*- coding: utf-8 -*-
from pyltp import CustomizedSegmentor
customized_segmentor = CustomizedSegmentor()  # 初始化实例
customized_segmentor.load_with_lexicon(‘基本模型‘, ‘个性模型‘, ‘用户字典‘) # 加载模型
words = customized_segmentor.segment(‘亚硝酸盐是一种化学物质‘)
print ‘\t‘.join(words)
customized_segmentor.release()

#词性标注

词性标注也是我们经常遇到的任务,也不多解释了
词性标注需要输入分词后的结果,所以请先参考下之前的按个分词部分,其返回的结果可以作为输入直接标注

# -*- coding: utf-8 -*-
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)  # 分词
    #默认可以这样输出
    # print ‘\t‘.join(words)
    # 可以转换成List 输出
    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()

运行结果: 前面是词语,后面是词性,词性的表述请参照这里
技术分享

命名实体识别

命名实体识别,主要是hi识别一些人名,地名,机构名等。
需要前面分词和词性标注作为输入

#注意,从这里开始,因为牵扯到的代码比较多,所以不是完成的代码,只是片段,要保证正常运行,请参照最后的完整代码附录
# -*- coding: utf-8 -*-
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

#测试分句子
#sentence_splitter()
#测试分词
words = segmentor(‘我家在昆明,我现在在北京上学。中秋节你是否会想到李白?‘)
#测试标注
tags = posttagger(words)
#命名实体识别
ner(words,tags)

运行结果
技术分享

命名实体的参照标记,也是请看这里

依存句法分析

依存句法依旧需要之前的两个输入,words 和 postags 分别为分词和词性标注的结果。
arc.head 表示依存弧的父节点词的索引,arc.relation 表示依存弧的关系。其具体的表述看这里

# -*- coding: utf-8 -*-
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()  # 释放模型

#测试分句子
#sentence_splitter()
#测试分词
words = segmentor(‘我家在昆明,我现在在北京上学。中秋节你是否会想到李白?还有,微博是MebiuW‘)
#测试标注
tags = posttagger(words)
#依存句法识别
parse(words,tags)

运行结果
技术分享

语义角色标注

arg.name 表示语义角色关系,arg.range.start 表示起始词位置,arg.range.end 表示结束位置。

# -*- coding: utf-8 -*-
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()  # 释放模型
#测试分句子
#sentence_splitter()
#测试分词
words = segmentor(‘我家在昆明,我现在在北京上学。中秋节你是否会想到李白?还有,微博是MebiuW‘)
#测试标注
tags = posttagger(words)
#命名实体识别
netags = ner(words,tags)
#依存句法识别
arcs = parse(words,tags)
#j角色标注
roles = role_label(words,tags,netags,arcs)

运行结果:

技术分享

角色对照看这里

结语

有点累,突然写不动了,就先写这些吧,有问题我们评论或者新浪微博@MebiuW 交流

参考

1、Pyltk 官方文档

参考本篇完整代码

可能有些打印有点杂乱,见谅

# -*- coding: utf-8 -*-
#作者:MebiuW
#微博:@MebiuW
#python 版本:2.7
#时间 2016/9/10
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)
    # 可以转换成List 输出
    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(‘###############以上为角色标注测试###############‘)
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    Python下的自然语言处理利器-LTP语言技术平台 pyltp 学习手札