未加星标

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

字体大小 | |
[开发(python) 所属分类 开发(python) | 发布者 店小二04 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

发表于:6天前阅读:76


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

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

默认标注器

默认标注器为每个单词分配同样的标记,尽管很平庸,但它也是有作用的,先看示例:

import nltk raw = "You are a good man, but i don't love you!" tokens = nltk.word_tokenize(raw) default_tagger = nltk.DefaultTagger('NN') tagged_words = default_tagger.tag(tokens) print(tagged_words)

结果为:

[('You', 'NN'), ('are', 'NN'), ('a', 'NN'), ('good', 'NN'), ('man', 'NN'), (',', 'NN'), ('but', 'NN'), ('i', 'NN'), ('do', 'NN'), ("n't", 'NN'), ('love', 'NN'), ('you', 'NN'), ('!', 'NN')]

DefaultTagger的构造函数接受一个标记字符串作为参数,生成一个默认标注器对象,从结果可以看到默认标注器把所有的词都标记为NN。

DefaultTagger::tag(tokens):对指定的单词列表进行标记,返回被标记后的单词列表。

DefaultTagger::evaluete(tagged_sents):使用已经被标记的句子评价标注器,返回正确率0~1.0。

from nltk.corpus import brown tagged_sents = brown.tagged_sents(categories='news') print(default_tagger.evaluate(tagged_sents))

结果为:

0.13089484257215028

我们可以看到我们自己创建的默认标注器正确率仅为0.13。

查询标注器

默认标注器对所有单词使用同一个标记,准确率太低,我们可以考虑指定不同的单词为不同的标记,先看一个示例:

# 对新闻文本进行频率分布,找出新闻文本最常用的100个单词 fd = nltk.FreqDist(brown.words(categories='news')) most_common_pairs = fd.most_common(100) most_common_words = [i[0] for i in most_common_pairs] # 对标记后的新闻文本进行条件频率分布,这样我们就可以找到指定单词最多的标记是哪一个 cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news')) # 找出最常用的100个单词的最多标记 likely_tags = dict((word, cfd[word].max()) for word in most_common_words) # 使用(单词-标记)字典作为模型,生成查询标注器 baseline_tagger = nltk.UnigramTagger(model=likely_tags) tagged_sents = brown.tagged_sents(categories='news') print(baseline_tagger.evaluate(tagged_sents))

结果为:

0.45578495136941344

这次我们创建的标注器的正确率为0.45,比我们的默认标注器要好很多。UnigramTagger类的构造函数接受一个(单词-标记)字典作为模型,可以直接生成一个标注器。事实上UnigramTagger和DefaultTagger类都继承自TaggerI,TaggerI具有tag和evaluete方法,所以UnigramTagger也具有tag和evaluete方法。

因为我们只指定了100个单词的标记,我们来看看我们创建的标注器对未指定的单词是如何标记的。

raw = "You are a good man, but i don't love you!" tokens = nltk.word_tokenize(raw) print(baseline_tagger.tag(tokens))

结果为:

[('You', None), ('are', 'BER'), ('a', 'AT'), ('good', None), ('man', None), (',', ','), ('but', 'CC'), ('i', None), ('do', None), ("n't", None), ('love', None), ('you', None), ('!', None)]

许多词被分配为None标签,这是因为它们不包含在100单词中。针对这种情况,我们可以给它们一个默认标记。换句话说我们要先使用查找表,如果它不能指定一个标记就使用默认标注器,这个过程叫做回退。

# 使用默认标注器作为回退 baseline_tagger2 = nltk.UnigramTagger(model=likely_tags, backoff=nltk.DefaultTagger('NN')) tagged_sents = brown.tagged_sents(categories='news') print(baseline_tagger2.evaluate(tagged_sents))

结果为:

0.5817769556656125

我们可以看到正确率提升了

如果我们增大单词数量,则正确率还会提升。

# 对新闻文本进行频率分布,找出新闻文本最常用的500个单词 fd = nltk.FreqDist(brown.words(categories='news')) most_common_pairs = fd.most_common(500) most_common_words = [i[0] for i in most_common_pairs] # 对标记后的新闻文本进行条件频率分布,这样我们就可以找到指定单词最多的标记是哪一个 cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news')) # 找出最常用的500个单词的最多标记 likely_tags = dict((word, cfd[word].max()) for word in most_common_words) # 使用(单词-标记)字典作为模型,生成查询标注器 baseline_tagger = nltk.UnigramTagger(model=likely_tags, backoff=nltk.DefaultTagger('NN')) tagged_sents = brown.tagged_sents(categories='news') print(baseline_tagger.evaluate(tagged_sents))

结果为:

0.6789983491457326

一元标注器

一元标注器基于一个简单的统计算法:对每个单词分配这个单词最有可能的标记。一元标注器的行为就像一个查询标注器,但是它不需要我们提供model,我们只需要提供训练样本也就是被标记的句子列表,标注器会使用这些样本进行训练,将所有词的最可能标记存储在一个字典里,例子如下:

import nltk from nltk.corpus import brown tagged_sents = brown.tagged_sents(categories='news') # 生成一元标注器 unigram_tagger = nltk.UnigramTagger(train=tagged_sents) print(unigram_tagger.evaluate(tagged_sents))

结果为:

0.9349006503968017

这个结果比我们前面的查询标注器要好很多,并且一元标注器不需要我们自己去统计每个单词最有可能的标记。

然而使用同一个数据集作为训练集和测试集不是一个好的做法,如果我们训练出来的标注器过拟合我们也不能知道,接下来我们要分离训练集和测试集,我们把数据集的90%作为训练集,10%作为测试集。

tagged_sents = brown.tagged_sents(categories='news') size = int(len(tagged_sents) * 0.9) train_sets = tagged_sents[:size] test_sets = tagged_sents[size:] # 生成一元标注器 unigram_tagger = nltk.UnigramTagger(train=train_sets) print(unigram_tagger.evaluate(train_sets)) print(unigram_tagger.evaluate(test_sets))

结果为:

0.9353630649241612

0.8115219774743347

我们可以看到一元标注器在测试集上的正确率为0.81

二元标注器

尽管我们对每个单词分配了这个标识符最有可能的标记,但是在不同的上下文环境中,单词是有可能是其他的标记的。所以一个单词的标记不仅仅和它自身有关系,还可能和它的前一个单词或者更前面的单词有关系。二元标注器就是一个可以考虑单词自身以及前一个单词的标注器。

tagged_sents = brown.tagged_sents(categories='news') size = int(len(tagged_sents) * 0.9) train_sets = tagged_sents[:size] test_sets = tagged_sents[size:] # 生成二元标注器 bigram_tagger = nltk.BigramTagger(train=train_sets) print(bigram_tagger.evaluate(train_sets)) print(bigram_tagger.evaluate(test_sets))

结果为:

0.7890434263872471

0.10186384929731884

二元标注器会考查一个单词本身和它前一个单词的标记,如果遇到一个新词,那么二元标注器就没法标记它,并且还会导致接下来的单词都没法标记,所以我们会看到二元标注器在测试集上正确率很低。

组合标注器

前面我们对查询标注器设置了一个回退标注器(默认标注器),事实上大部分的NLTK标注器都可以设置回退标注器,这样我们就可以把二元标注器、一元标注器、默认标注器组合起来得到一个组合标注器,例如我们可以按照下列方式组合:

尝试使用bigram标注器标注单词。 如果bigram标注器无法找到一个标记,尝试unigram标注器。 如果unigram标注器无法找到一个标记,使用默认标注器。

代码如下:

import nltk from nltk.corpus import brown # 划分训练集和测试集 tagged_sents = brown.tagged_sents(categories='news') size = int(len(tagged_sents) * 0.9) train_sets = tagged_sents[:size] test_sets = tagged_sents[size:] # 训练标注器,并把它们组合起来 t0 = nltk.DefaultTagger('NN') t1 = nltk.UnigramTagger(train=train_sets, backoff=t0) t2 = nltk.BigramTagger(train=train_sets, backoff=t1) # 查看标注器性能 print(t2.evaluate(train_sets)) print(t2.evaluate(test_sets))

结果为:

0.9735641453364413

0.8459085019435861

从结果我们可以看到相比于一元标注器,我们的组合标注器还是有提高的。

总结 TaggerI::tag(tokens) :对指定的单词列表进行标记,返回被标记后的单词列表 TaggerI::evaluete(tagged_sents) :使用已经被标记的句子评价标注器,返回正确率0~1.0

DefaultTagger, UnigramTagger, BigramTagger都继承至TaggerI

DefaultTagger

默认标注器的构造函数接受一个标记作为参数,生成标注器

UnigramTagger

一元标注器接受被标记的句子列表作为参数,生成标注器

BigramTagger

二元标注器接受被标记的句子列表作为参数,生成标注器

其他章节链接

Python NLTK学习1(Text对象)

Python NLTK学习2(FreqDist对象)

Python NLTK学习3(语料库)

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

Python NLTK学习5(词性标注)

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

本文开发(python)相关术语:python基础教程 python多线程 web开发工程师 软件开发工程师 软件开发流程

分页:12
转载请注明
本文标题:Python NLTK学习6(创建词性标注器)
本站链接:http://www.codesec.net/view/522965.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(python) | 评论(0) | 阅读(172)