前面我分享了一下使用NLTK进行文本数据的预处理工作,这里继续分享一下NLTK的词性标注。
词性(POS)在小学的语文课或者英语课中已经多次强调了其含义,这里就不赘述了。就拿英语来说,它在新闻和其它领域往往都有许多已经被标注的语料库,所以已经有大量的算法在这一领域中得到应用。但是在特定的应用场景中,POS的判定可能有些失灵。对于这些用例,可能需要重新建立一个标注器。
在讨论POS标注时,有一个公认的标准就是Penn Treebank的POS标记库。其原本是一个项目的名称,该项目主要用于对相关语料进行标注,标注内容包括词性标注及句法分析。其语料来源为1989年的华尔街日报。
下面就几个常见的标注器的使用进行一些简单的示例分享。
1. Stanford 标注器
从名字就可以看出其出身,斯坦福大学。又想感叹一句,国内外的大学差距怎么那么大,人家一个搞学术的学校也能出商用的项目和代码,而国内的呢?搞学术的都跟闹着玩一下,评价一个教授的好坏就是看他出了多少篇论文,而其学术对于科技进步的贡献如何评价却没有人去关注。收!回到本文的内容,使用Stanford标注器需要下载一个模块,其下载地址如下: https://nlp.stanford.edu/software/stanford-postagger-2017-06-09.zip
代码:
from nltk.tag.stanford import StanfordPOSTagger import nltk s = 'The tagger was originally written by Kristina Toutanova. ' print(nltk.pos_tag(s)) stan_tagger = StanfordPOSTagger('stanford-postagger-2017-06-09/models/english-bidirectional-distsim.tagger', 'stanford-postagger-2017-06-09/stanford-postagger-3.8.0.jar') tokens = nltk.word_tokenize(s) print(tokens) print(stan_tagger.tag(tokens))
结果:
[('T', 'NNP'), ('h', 'NN'), ('e', 'NN'), (' ', 'NNP'), ('t', 'VBZ'), ('a', 'DT'), ('g', 'NN'), ('g', 'NN'), ('e', 'NN'), ('r', 'NN'), (' ', 'NNP'), ('w', 'VBZ'), ('a', 'DT'), ('s', 'JJ'), (' ', 'NN'), ('o', 'IN'), ('r', 'NN'), ('i', 'NN'), ('g', 'VBP'), ('i', 'NN'), ('n', 'VBP'), ('a', 'DT'), ('l', 'NN'), ('l', 'NN'), ('y', 'NN'), (' ', 'NNP'), ('w', 'NN'), ('r', 'NN'), ('i', 'NN'), ('t', 'VBP'), ('t', 'NN'), ('e', 'NN'), ('n', 'JJ'), (' ', 'NN'), ('b', 'NN'), ('y', 'NN'), (' ', 'NNP'), ('K', 'NNP'), ('r', 'NN'), ('i', 'NN'), ('s', 'VBP'), ('t', 'NN'), ('i', 'NN'), ('n', 'VBP'), ('a', 'DT'), (' ', 'JJ'), ('T', 'NNP'), ('o', 'NN'), ('u', 'NN'), ('t', 'VBD'), ('a', 'DT'), ('n', 'JJ'), ('o', 'NN'), ('v', 'NN'), ('a', 'DT'), ('.', '.'), (' ', 'NN')]
['The', 'tagger', 'was', 'originally', 'written', 'by', 'Kristina', 'Toutanova', '.']
[('The', 'DT'), ('tagger', 'NN'), ('was', 'VBD'), ('originally', 'RB'), ('written', 'VBN'), ('by', 'IN'), ('Kristina', 'NNP'), ('Toutanova', 'NNP'), ('.', '.')]
从结果中可以看出,首先需要进行分词,不然系统会把每个字符看作一个单词去进行词性标注。这些标红的是其单词的词性标识,具体含义见下表:
标识 | 含义 |
---|---|
NNP | 专用名词的单数形式 |
DT | 限制词 |
RB | 副词 |
VBD | 动词过去式 |
2. 顺序性标注器
这里从Brown语料库中获取news类型的数据,然后对其POS标签出现的频率进行观察。
代码:
from nltk.corpus import brown import nltk tags = [tag for (word,tag) in brown.tagged_words(categories='news')] freq_tags = nltk.FreqDist(tags) print(freq_tags.items())
结果:
dict_items([('AT', 8893), ('NP-TL', 741), ('NN-TL', 2486), ('JJ-TL', 689), ('VBD', 2524), ('NR', 495), ('NN', 13162), ('IN', 10616), ('NP$', 279), ('JJ', 4392), ('``', 732), ("''", 702), ('CS', 1509), ('DTI', 205), ('NNS', 5066), ('.', 4452), ('RBR', 88), (',', 5133), ('WDT', 343), ('HVD', 262), ('VBZ', 519), ('CC', 2664), ('IN-TL', 164), ('BEDZ', 716), ('VBN', 2269), ('NP', 6866), ('BEN', 212), ('TO', 1237), ('VB', 2440), ('RB', 2166), ('DT', 589), ('PPS', 1056), ('DOD', 64), ('AP', 923),......
从结果中可以看出NN出现的次数比较多。这里针对它创建一个简单的POS标注器,用于测试文本分配NN标签。
代码:
brown_tagged_sents = brown.tagged_sents(categories='news') default_tagger = nltk.DefaultTagger('NN') print(default_tagger.evaluate(brown_tagged_sents))
结果:
0.13089484257215028
这里使用默认的顺序性标注器,并调用evaluate函数进行评估,其预测准确的概率只有13%。
2.1 N-gram 标注器
N-gram 标注器是SequentialTagger的一个子类,它会在其所在的上下文环境中标注出前n个单词,并预测给定token的POS标签。
代码:
from nltk.tag import UnigramTagger from nltk.tag import BigramTagger from nltk.tag import TrigramTagger train_data = brown_tagged_sents[:int(len(brown_tagged_sents) * 0.9)] test_data = brown_tagged_sents[int(len(brown_tagged_sents) * 0.9):] # The backoff tagger that should be used for this tagger. unigram_tagger = UnigramTagger(train_data, backoff=default_tagger) print(unigram_tagger.evaluate(test_data)) trigram_tagger = TrigramTagger(train_data, backoff=unigram_tagger) print(trigram_tagger.evaluate(test_data)) biggram_tagger = BigramTagger(train_data, backoff=trigram_tagger) print(biggram_tagger.evaluate(test_data))
结果:
0.8361407355726104
0.8401275789893352
0.8417223163560251
可以看出预测的准确率都高了很多,其中bigram是考虑给定单词的前后一个单词,其标签以元组的形式来关联被测试单词所得到的标签。Trigram是兼顾给定单词的前两个单词。
2.2 正则表达式标注器
顺序性标注器中还有一种是正则表达式标注器,正如名字一样,其基础是正则表达式。例如以”ness“结尾的单词一般都会是形容词,以"ly"结尾的是副词等。其主要是使用RegexpTagger类,由于其方法简单粗暴,这里就不详细描述了。
3. 命名实体识别(NER)
NER 主要是由实体名,位置和组织构成,可以被视作一个顺序性的标签化问题,可以利用上下文语境和其它相关特性来标签化这些命名实体。NLTK提供的命名实体提取方法是ne_chunk()。
代码:
import nltk from nltk import ne_chunk sent = 'The tagger was originally written by Kristina Toutanova. He is working at Ebay in Shanghai office' print(ne_chunk(nltk.pos_tag(nltk.word_tokenize(sent)), binary=False))
结果:
(S
The/DT
tagger/NN
was/VBD
originally/RB
written/VBN
by/IN
(PERSON Kristina/NNP Toutanova/NNP)
./.
He/PRP
is/VBZ
working/VBG
at/IN
(ORGANIZATION Ebay/NNP)
in/IN
(GPE Shanghai/NNP)
office/NN)
可以看出它识别除了人Kristina Toutanova,所属的组织Ebay和位置Shanghai。现在市面上已经出现了各式各样的NER标注器,并被应用于各种领域如医疗,生物学等,它们都会训练出自己的标注器。这里推荐一个NER:Calaris,Https://code.google.com/p/python-calaris
最后说两句:
这里只是个人读书后的一个分享,主要目的是想让大家少走些弯路,同时也算给自己读书做一个笔记。当学到这里的时候才发现NLP这个领域真的是博大精深,光一个词性标注就有很多研究方向,同时其对统计学,机器学习等数学基础要求又是很高。我也是看了个似懂非懂的样子,不过我相信,只要我坚持看,应该可以做到应用没有问题。
这里只是列举了一些可以用代码展示的标注器,其实除了这些还有很多需要大家带着兴趣去探索。