用于实体识别的基本技术是分块(chunking),如下将多个单词合并成句子的一个部分就是分块。
分块示意图
名词短语分块
名词短语分块的组成:限定词(a/an/the等)AT + 一个或多个形容词(JJ)+ 名词(NN)组成。
import nltk
sent = "she is a beautiful girl and a good daughter"
#分词
words = sent.split()
print("分词结果:",words)
#标注词性
t1 = nltk.DefaultTagger("NN")
patterns = [
(r'.*ing$',"VBG"),
(r'.*ed$',"VBD"),
(r'.*es$',"VBZ"),
(r'.*ould$',"MD"),
(r'.*\'s$',"NN"),
(r'.*s$',"NNS"),
(r'^-?[0-9]+(.[0-9]+)?$',"CD"),
(r'.*',"NN") #匹配所有单词,默认标注为NN
]
t2 = nltk.RegexpTagger(patterns,backoff=t1)
words_tagged = nltk.corpus.brown.tagged_words(categories="news")
cfd = nltk.ConditionalFreqDist(words_tagged)
words_pos = {w:cfd[w].max() for w in cfd.conditions()}
t3 = nltk.UnigramTagger(model=words_pos,backoff=t2)
# print(nltk.corpus.brown.categories())
# brown_tagged_sents = nltk.corpus.brown.tagged_sents(categories='news')
# print(brown_tagged_sents)
# print(t3.evaluate(brown_tagged_sents))
words = t3.tag(words)
print(words)
grammar = "NP:{<AT>?<JJ>*<NN>}"
cp = nltk.RegexpParser(grammar)
result = cp.parse(words)
print(result)
result.draw()
分块
模式标记
一个标记模式是一个用尖括号分隔的词性标记序列,如<DT>?<JJ>*<NN>。和上面的程序例子差不多。
探索文本语料库
在句子中提取词性序列的短语使用分块器更方便。将布朗语料库中词性组合为V开头的词性,中间to后面也是V开头的词性的词组找出来。至于它这个tree就让我难以理解了。
import nltk
cp = nltk.RegexpParser("chunk:{<V.*> <TO> <V.*>}")
brown = nltk.corpus.brown
for sent in brown.tagged_sents():
tree = cp.parse(sent)
for subtree in tree.subtrees():
if subtree.label() == 'chunk':print(subtree)
加缝隙
为不包含在块中的标识符序列定义一个缝隙
下面的例子,barked/VBD at/IN就是一个缝隙。
[the/DT little/JJ yellow/JJ dog/NN] barked/VBD at/IN [the/DT cat/NN]
加缝隙是为了在块中去除一个标识符序列,如果整块都匹配这个标识符序列,则这个块将会被去除,如果在中间标识符部分将会被去除,以前的一个块变成两个块。如果是在块的两边去除这个标识符之后块将会减小。
import nltk
#块的震泽表达式,匹配的名字叫做NP
# 第一行匹配任何东西
# 第二行将句子中的VBD或者IN单独提取出来作为一部分,其他的合并成一部分
grammar = r'''
NP:
{<.*>+}
}<VBD|IN>+{
'''
#文本
sentence = [("the", "DT"), ("little", "JJ"), ("yellow", "JJ"),
("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")]
#解析块正则表达式
cp = nltk.RegexpParser(grammar)
#输出句子内容
print(cp.parse(sentence))
运行结果
在这个程序的基础上再次来理解一下前面个那个tree使用RegexpParser 的对象解析句子之后会得到句子的结构树,从运行结果看,树的根节点为s 树有四个部分(NP + barked + at + NP),其中的NP是我们的块正则表达式中命名的。
从运行结果可以看到,使用 }......{ 这样的正则表达式将两个符号中间的内容单独分离了出去,剩下的内容单独成为两块。
块的表示:标记与树
用IOB标记表示块
I 内部 ,O外部 , B开始,标注的时候需要加上块类型的后缀,如果是内部的NP块,则标注为I-NP
IOB标记表示块还有一种就是上面的树的表示方法
树结构表示块
网友评论