词性(Part of Speech, POS)。最常用的POS notification是宾州树库(Penn Tree Bank, PTB)标记集。
Copy # 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标注器示例
Copy # 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标签的频率分布:
Copy # 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的准确性。
Copy # 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标签。
Copy # 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标签。
正则表达式标注器
Copy # 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体系所标注的实体不仅仅这三种实体。
Copy # 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的标注器,具有更高的准确率。
Copy # 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。