Python NLTK学习8(正则表达式分块器)

本系列博客为学习《用Python进行自然语言处理》一书的学习笔记。

引言

一个句子在分成一个个词后,我们还可以将一个或多个连续的词分成一块。分成的块通常代表一个整体,例如在句子"We saw the yellow dog"中,"the yellow dog"可以看作是一个块,像这样的块我们一般称为名词短语块。分块是用于实体识别的基本技术。

名词短语分块

名词短语分块也叫做NP-分块,NP-分块信息最有用的来源之一是词性标记,所以我们一般在分块前都会进行词性标注。

正则表达式分块器

为了创建一个NP-块,我们需要定义NP-块的块语法。正则表达式分块器接受正则表达式规则定义的语法来对文本进行分块,我们先看一个例子:

import nltk

# 分词
text = "the little yellow dog barked at the cat"
sentence = nltk.word_tokenize(text)

# 词性标注
sentence_tag = nltk.pos_tag(sentence)
print(sentence_tag)

# 定义分块语法
# 这个规则是说一个NP块由一个可选的限定词后面跟着任何数目的形容词然后是一个名词组成
# NP(名词短语块) DT(限定词) JJ(形容词) NN(名词)
grammar = "NP: {<DT>?<JJ>*<NN>}"

# 进行分块
cp = nltk.RegexpParser(grammar)
tree = cp.parse(sentence_tag)
tree.draw()

示例中我们先进行分词,词性标注,之后我们定义了一个分块语法"NP: {...}",该语法中的NP就是代表我们的块名称,一对{}就是把大括号中语法匹配到的词做为一块,使用该语法构造出一个正则表达式分块器就可以对标注词性的文本进行分块,分块结果是一个Tree对象。

该示例的结果为:

[('the', 'DT'), ('little', 'JJ'), ('yellow', 'JJ'), ('dog', 'NN'), ('barked', 'VBD'), ('at', 'IN'), ('the', 'DT'), ('cat', 'NN')]

从分块结果中我们可以看到"the little yellow dog"和"the cat"都被正确的分块为NP-块。

多条规则的正则表达式分块器

上面的例子只有一条语法规则,如果面对复杂的情况就不太适用,我们可以定义多条分块规则。面对多条规则,分块器会轮流应用分块规则,依次更新块结构,所有的规则都被调用后才返回。我们先看一个示例:

import nltk

# 分词
text = "Lucy let down her long golden hair"
sentence = nltk.word_tokenize(text)

# 词性标注
sentence_tag = nltk.pos_tag(sentence)
print(sentence_tag)

# 定义分块语法
# NNP(专有名词) PRP$(格代名词)
# 第一条规则匹配可选的词(限定词或格代名词),零个或多个形容词,然后跟一个名词
# 第二条规则匹配一个或多个专有名词
# $符号是正则表达式中的一个特殊字符,必须使用转义符号\来匹配PP$
grammar = r"""
    NP: {<DT|PRP\$>?<JJ>*<NN>}
        {<NNP>+}
"""

# 进行分块
cp = nltk.RegexpParser(grammar)
tree = cp.parse(sentence_tag)
tree.draw()

该示例的结果为:

[('Lucy', 'NNP'), ('let', 'VBD'), ('down', 'RP'), ('her', 'PRP$'), ('long', 'JJ'), ('golden', 'JJ'), ('hair', 'NN')]

从分块结果可以看到"Lucy"和"her long golden hair"都符合我们的分块预期。

加缝隙

上面两个例子我们都是根据定义的块规则来找到块,反过来想,我们可以定义非块结构的规则,然后把找到的非块给排除掉。以上的过程叫做加缝隙,加缝隙是从一大块中去除一个标识符序列的过程。如果匹配的标识符序列出现在块的中间,这些标识符会被去除,在以前只有一个块的地方留下两个块。如果序列在块的周边,这些标记被去除,留下一个较小的块。我们先看一个例子:

import nltk

# 分词
text = "the little yellow dog barked at the cat"
sentence = nltk.word_tokenize(text)

# 词性标注
sentence_tag = nltk.pos_tag(sentence)
print(sentence_tag)

# 定义缝隙语法
# 第一个规则匹配整个句子
# 第二个规则匹配一个或多个动词或介词
# 一对}{就代表把其中语法匹配到的词作为缝隙
grammar = r"""
NP: {<.*>+}
    }<VBD|IN>+{
"""
cp = nltk.RegexpParser(grammar)

# 分块
tree = cp.parse(sentence_tag)
tree.draw()

该示例的结果为:

[('the', 'DT'), ('little', 'JJ'), ('yellow', 'JJ'), ('dog', 'NN'), ('barked', 'VBD'), ('at', 'IN'), ('the', 'DT'), ('cat', 'NN')]

该示例的结果结果和第一个例子的结果一致。

NLTK Tree

树继承自列表,树的孩子是以列表的方式进行存储的。树的孩子可以是一个叶子结点或者子树结点,叶子结点没有孩子,子树结点有孩子,子树也是树。树有一个标签属性,可以使用.label()方法进行查看。如下图就是[('the', 'DT'), ('little', 'JJ'), ('yellow', 'JJ'), ('dog', 'NN'), ('barked', 'VBD'), ('at', 'IN'), ('the', 'DT'), ('cat', 'NN')]分块后的树结构: 树根的标签为'S',它有4个孩子,4个孩子以列表的方式存储。树根的孩子0和孩子3是子树,它们的标签是'NP'。树根的孩子1和孩子2是叶子,它们是元组对象。

总结

  • RegexpParser(grammar):构造函数,接受分块语法,返回一个正则表达式分块器
  • RegexpParser::parse(tokens):针对标注词性的列表进行分块,返回一个Tree对象
  • Tree::draw():绘制树形结构
  • Tree::label():返回树的标签
  • Tree::subtrees():返回所有的子树,包括子树的子树
  • Tree::leaves():返回所有的叶子,包括子树的叶子

NLTK词性标注符号含义

  • CC 连接词

  • CD 基数词

  • DT 限定词

  • EX 存在

  • FW 外来词

  • IN 介词或从属连词

  • JJ 形容词或序数词

  • JJR 形容词比较级

  • JJS 形容词最高级

  • LS 列表标示

  • MD 情态助动词

  • NN 常用名词 单数形式

  • NNS 常用名词 复数形式

  • NNP 专有名词 单数形式

  • NNPS 专有名词 复数形式

  • PDT 前位限定词

  • POS 所有格结束词

  • PRP 人称代词

  • PRP$ 所有格代名词

  • RB 副词

  • RBR 副词比较级

  • RBS 副词最高级

  • RP 小品词

  • SYM 符号

  • TO to 作为介词或不定式格式

  • UH 感叹词

  • VB 动词基本形式

  • VBD 动词过去式

  • VBG 动名词和现在分词

  • VBN 过去分词

  • VBP 动词非第三人称单数

  • VBZ 动词第三人称单数

  • WDT 限定词

  • WP 代词

  • WP$ 所有格代词

  • WRB 疑问代词

其他章节链接

Python NLTK学习1(Text对象)

Python NLTK学习2(FreqDist对象)

Python NLTK学习3(语料库)

Python NLTK学习4(条件频率分布)

Python NLTK学习5(词性标注)

Python NLTK学习6(创建词性标注器)

Python NLTK学习7(对中文昵称进行性别分类)

Python NLTK学习8(正则表达式分块器)

Python NLTK学习9(评估分类器的方法)

Python NLTK学习10(评估分块器)

Python NLTK学习11(命名实体识别和关系抽取)


赞助作者写出更好文章


您还未登录,登录GitHub账号发表精彩评论

 GitHub登录


最新评论

    还没有人评论...

 

 

刘杰

29岁, 现居苏州

微信:

CoderJieLiu

邮箱:

coderjie@outlook.com

Github:

https://github.com/BurnellLiu

简介:

弱小和无知不是生存的障碍,傲慢才是!

Think Twice, Code Once!

本站: 登录 注册

苏ICP备16059872号-1 苏ICP备16059872号-2 . Copyright © 2017. http://www.coderjie.com. All rights reserved.

账号登录

注册 忘记密码