分块的意义何在?
以我现在的水平我觉得,将句子相关的部分合并成一块之后,对于理解句子的机构,提取句子中的关键信息比较方便。
import nltk
from nltk.corpus import brown
tagged_sents = brown.tagged_sents()
#简单的正则比表达式对句子进行分块,ALL是任意取的名字,{}表示匹配其中的内容
#<>匹配的是词性如<NN>匹配名词 <.*>+匹配所有词性 至少一次
#}{中间的内容是为分块加间隙,将词性为DT的单独隔离
grammar = '''
ALL:{<.*>+}
}<DT>+{
'''''
#进行分块的都应该是下面这样的句子,(单词,词性)组合
sentence = [("the", "DT"), ("little", "JJ"), ("yellow", "JJ"), ("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")]
#解析分块正则表达式
cp = nltk.RegexpParser(grammar)
#分块句子
data = cp.parse(sentence)
#输出分块结果的时候有的单词会被单独出来,不是树结构,也没有label方法
for subtree in data:
if isinstance(subtree,type(data)):
print(subtree.label())
print(subtree)
print("句子分块的树表示:\n",data)
print("句子分块的IOB表示")
print(nltk.chunk.tree2conlltags(data))
print('-----------------------------------------------')
#简单的评估和基准
from nltk.corpus import conll2000
#空正则表达式,所有单词都标注为 O(块之外)
cp = nltk.RegexpParser("")
test_sents = conll2000.chunked_sents("test.txt",chunk_types=['NP'])
#输出数据的树表示
print(test_sents)
tree2conlltag = [nltk.chunk.tree2conlltags(tree) for tree in test_sents ]
#输出第11条数据的IOB表示
print(tree2conlltag[10])
print(cp.evaluate(test_sents))
#尝试一个初级的正则表达式分类器
gramma = '''
NP:{<[CDJNP].*>+}
O:{<^[CDJNP].*>+}
'''
cp2 = nltk.RegexpParser(gramma)
print(cp2.evaluate(test_sents))
print("去除所有块中非NP的块")
test_sents = [tree for tree in test_sents if isinstance(tree,type(test_sents)) and
tree.label() == 'NP'
]
#去除掉其中除NP之外的块,再次测试,结果应该是100%
print(cp2.evaluate(test_sents))
#使用unigram标注器来进行分块
#这个的大体意思应该是将每个单词分配一个IOB标记以此来对句子进行分块
#所以训练数据也是使用的单词词性 + 块标记
train_sents = conll2000.chunked_sents("train.txt",chunk_types=['NP'])
test_sents = conll2000.chunked_sents("test.txt",chunk_types=['NP'])
#将分块句子转换为训练数据(词性 + IOB标记)
#下面的这个拼接就很灵性,先按照树拼接为列表,然后将多个列表拼接成列表
train_set = [[(p,t) for (w,p,t) in nltk.chunk.tree2conlltags(tree)]
for tree in train_sents
]
print("一条查询标注器的训练数据:",train_set[2])
chunker = nltk.UnigramTagger(train_set)
test_set = [[(p,t)for (w,p,t) in nltk.chunk.tree2conlltags(tree)]
for tree in test_sents
]
print(chunker.evaluate(test_set))
总结
- 正则表达式匹配的是词性,
- 分块的对象(parse()的参数)是单词词性元组
- 查询标注器的训练数据(单词,词性)组成句子链表,句子链表再组成训练数据。
- 评估的时候数据也应该和训练数据一样。
- chunk模块下有树/IOB标记 之间的相互转换函数
网友评论