自然语言处理(NLP)-NLTK入门学习(二)

前面我分享了一下使用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 动词过去式
这里就不花篇幅去展开讲其全部含义了,感兴趣的可以自行Google POS标志库。一个典型的标注器需要大量的训练数据,它主要工作就是为各个句子标上POS标签,是一个纯手工的操作。为此有一个语言数据联盟(https://www.ldc.upenn.edu/简称:LDC)的组织,那里的人们花了很多时间来研究不同语言的标注,不同的文本种类及不同的标注操作,如词性的标注、句法分析标注,以及对话标注等。

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这个领域真的是博大精深,光一个词性标注就有很多研究方向,同时其对统计学,机器学习等数学基础要求又是很高。我也是看了个似懂非懂的样子,不过我相信,只要我坚持看,应该可以做到应用没有问题。

这里只是列举了一些可以用代码展示的标注器,其实除了这些还有很多需要大家带着兴趣去探索。


猜你喜欢

转载自blog.csdn.net/maizi1045/article/details/80723746