[1-3]词性

词性(Part of Speech, POS)。最常用的POS notification是宾州树库(Penn Tree Bank, PTB)标记集。

# POS tagging 
>>>import nltk
>>>from nltk import word_tokenize
>>>s="I was watching TV"
>>>print nltk.pos_tag(word_tokenize(s))

# all nouns
>>>tagged=nltk.pos_tag(word_tokenize(s))
>>>allnoun=[word for word,pos in tagged if pos in ['NN','NNP'] ]

nltk.pos_tag标注器在内部采用了maxnet分类器训练模型,预测一个具体的单词属于哪类标签。

NLTK封装了许多预先训练的标注器,如斯坦福工具等。

一个常见的POS标注器示例

# Stanford POS tagger 
# 需要从Stanford网站下载斯坦福标注器,放到文件夹中
>>>from nltk.tag.stanford import POSTagger
>>>import nltk
>>>stan_tagger=POSTagger('models/english-bidirectional-distdim.tagger','standford-postagger.jar')
>>>tokens =nltk.word_tokenize(s)
>>>stan_tagger.tag(tokens)

综上,主要以两种方式使用NLTK,实现标注任务

(1)在测试数据上应用NLTK或其他库中预先训练的标注器。这两种标注器足以应付任何非特定领域的语料库,纯英文文本的POS标注任务。

(2)构建或训练在测试数据使用的标注器,这用于处理非常具体的用例,开发自定义的标注器。

标注器

一个典型的标注器采用了大量训练数据,并且句子的每个单词上都附上了POS标签进行标注。标注基本上是手工劳动。

通常情况下,我们将词性标注问题视为序列标注问题或分类问题。在序列标注问题或分类问题中,对于给定单词,人们试图使用通用的判别模型来预测正确的标签。

布朗语料库中POS标签的频率分布:

# POS tags freq distribtuion
>>>from nltk.corpus import brown
>>>import nltk
>>>tags = [tag for (word, tag) in brown.tagged_words(categories='news')]
>>>print nltk.FreqDist(tags)

NN是最频繁的标签。下面构建一个非常朴素的POS标注器,将NN作为标签分配给所有测试单词。可以使用NLTK的DefaultTagger函数完成这个任务。evaluate函数给出了预测单词POS的准确性。

# default tagger
>>>brown_tagged_sents = brown.tagged_sents(categories='news')
>>>default_tagger = nltk.DefaultTagger('NN')
>>>print default_tagger.evaluate(brown_tagged_sents)
0.13

DefaultTagger是基类SequentialBackoffTagger的一部分,它基于序列(Sequence)进行标注。标注器试图基于上下文对标签建立模型,如果它不能够正确预测标签,那么它会咨询BackoffTagger。一般来说,DefaultTagger可以作为一个BackoffTagger。

序列标注器

N元标注器

N元标注器是SequentialTagger的子类。标注器接受上下文的前n个单词,预测给定单词的POS标签。

# N-gram taggers

>>>from nltk.tag import UnigramTagger
>>>from nltk.tag import DefaultTagger
>>>from nltk.tag import BigramTagger
>>>from nltk.tag import TrigramTagger
# we are dividing the data into a test and train to evaluate our taggers.
>>>train_data= brown_tagged_sents[:int(len(brown_tagged_sents) * 0.9)]
>>>test_data= brown_tagged_sents[int(len(brown_tagged_sents) * 0.9):]
>>>unigram_tagger = UnigramTagger(train_data,backoff=default_tagger)
>>>print unigram_tagger.evaluate(test_data)
0.826
>>>bigram_tagger= BigramTagger(train_data, backoff=unigram_tagger)
>>>print bigram_tagger.evaluate(test_data)
0.835
>>>trigram_tagger=TrigramTagger(train_data,backoff=bigram_tagger)
>>>print trigram_tagger.evaluate(test_data)
0.833

Unigram只考虑标签的条件概率,预测每个给定单词的最常见标签。bigram_tagger考虑给定单词及其前一个单词的标签,以元组标签形式,给出测试单词的给定标签。

TrigramTagger的覆盖率相对较低,实例的准确率会比较高,UnigramTagger的覆盖率较高。为了处理精确率和召回率之间的权衡,这里组合了这三种标注器。首先,对于给定的单词序列,程序会先询问trigram来预测标签,如果没找到给定单词序列的标签,那么通过Backoff回退到BigramTagger,如果还是找不到就回退到UnigramTagger,最后通过Backoff回退到NN标签。

正则表达式标注器

# Regex tagger 

>>>from nltk.tag.sequential import RegexpTagger
>>>regexp_tagger = RegexpTagger(
         [( r'^-?[0-9]+(.[0-9]+)?$', 'CD'),   # cardinal numbers
          ( r'(The|the|A|a|An|an)$', 'AT'),   # articles
          ( r'.*able$', 'JJ'),                # adjectives
          ( r'.*ness$', 'NN'),         # nouns formed from adj
          ( r'.*ly$', 'RB'),           # adverbs
          ( r'.*s$', 'NNS'),           # plural nouns
          ( r'.*ing$', 'VBG'),         # gerunds
          (r'.*ed$', 'VBD'),           # past tense verbs
          (r'.*', 'NN')                # nouns (default)
          ])
>>>print regexp_tagger.reg("I will be flying".split())
>>>print regexp_tagger.evaluate(test_data)
0.3036

如果将若干个正则表达式标注器进行结合,可能可以提高性能。

布里尔标注器

布里尔标注器是基于变换的标注器,其思想是,从猜测给定标签开始,在接下来的迭代中,基于标注器学习到的下一组规则,返回并修改错误。这也是监督的标注方式。

如果标注器从准确率一般的Unigram/Bigram标注器开始,然后使用布里尔标注器,无需寻找三元组,而是基于标签、位置和单词本身,寻找规则。例如:

当前一个单词是TO时,使用VB替代NN。

使用一些迭代和相对优化的规则,布里尔标注器的性能可以超过一些N元标注器。但是在训练集中,切勿使标注器产生过拟合。

基于标注器的机器学习

例如最大熵分类器MEC——判别模型

基于隐马尔可夫模型HMM和条件随机场CRF——生成模型

命名实体识别

一般来说,NER由名称、位置和组织构成。有一些NER体系所标注的实体不仅仅这三种实体。

# NER tagger 
>>>import nltk
>>>from nltk import ne_chunk
>>>from nltk import word_tokenize
>>>sent = "Mark is studying at Stanford University in California"
>>>print(ne_chunk(nltk.pos_tag(word_tokenize(sent)), binary=False))

ne_chunking方法可以识别人(姓名,name)、地点(位置,location)和组织。如果将binary设置为True,那么它将为整棵句子树提供输出,标注一切信息。如果是False,它将提供详细的个人、地点和组织信息,与先前使用斯坦福NER标注器的示例一样。

斯坦福NER的标注器,具有更高的准确率。

# NER stanford tagger 

>>>from nltk.tag.stanford import NERTagger
>>>st = NERTagger('<PATH>/stanford-ner/classifiers/all.3class.distsim.crf.ser.gz',...               '<PATH>/stanford-ner/stanford-ner.jar')
# <PATH> will be the relative path where you downloaded the tagger 
>>>st.tag('Rami Eid is studying at Stony Brook University in NY'.split())
#http://nlp.stanford.edu/software/ 

QA

在POS标注之前,可以删除停用词吗?

不能。如果删除了停用词,就失去了上下文,一些POS标注器(预训练模型)使用单词上下文作为特征,赋予给定单词POS。

Last updated

Was this helpful?