您的位置:首页 > 编程语言 > Python开发

自然语言处理——自动标注词性

2017-09-11 14:06 597 查看
本文探讨以不同的方式给文本自动添加词性标记。
首先加载要使用的数据。

import nltk
from nltk.corpus import brown

brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')

1、默认标注器

最简单的标注器是为每个标识符分配同样的标记。这似乎是一个相对普通的方法,但为标注器的性能建立了一个重要的标准。为了得到最好的效果,我们用最有可能的标记标注每个词。通过下例找出哪个标记是最有可能的。

tags = [tag for (word, tag) in brown.tagged_words(categories='news')]

tag = nltk.FreqDist(tags).max

>>>'NN'

我们现在可以创建一个将所有词都标注为NN的标注器。

raw = 'I do not like green egg and ham, I do not like them Sam I am!'
tokens = nltk.word_tokenize(raw)
default_tagger = nltk.DefaultTagger('NN')
default_tagger.tag(tokens)

不出所料,这种方法的表现相当不好。在一个典型的语料库中,它只正确标注了八分之一的标识符,如下列所示:

default_tagger.evaluate(brown_tagged_sents)
# 0.13089484257215028

默认的标注器给每个单独的词分配标记,即使是之前从未遇到过的词。碰巧的是,在处理几千词的英文文本时发现,大多数新名词都是名词。这意味着,默认标注器可以帮助我们提高语言处理系统的稳定性。

2、正则表达式标注器
正则表达式标注器基于匹配模式分配标记给标识符。例如,一般情况下认为任一以ed结尾的词都是动词过去分词,任一以‘s结尾的词都是名词所有格。下例中可以用正则表达式的列表来表示这些。

patterns = [
(r'.*ing$', 'VBG'),                                # gerunds
(r'.*ed$', 'VBD'),                                 # simple past
(r'.*es$', 'VBZ'),                                 # 3rd singular present
(r'.*ould$', 'MD'),                                # modals
(r'.*\'s$', 'NN$'),                                # possessive nouns
(r'.*s$', 'NNS'),                                  # plural nouns
(r'^-?[0-9]+(.[0-9]+)?$', 'CD'),                 # cardinal numbers
(r'.*', 'NN')                                      # nouns (deafult)
]
这些是按顺序处理的,第一个匹配上的会被使用。现在建立一个标注器,并用它来标注句子。

regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger.tag(brown_sents[3])
regexp_tagger.evaluate(brown_tagged_sents)


# 0.20326391789486245
我们发现有大约五分之一是正确的。

3、查询标注器

很多高频词没有NN标记,我们找出100个最频繁的词,存储它们最有可能的标记,然后我们可以使用这个信息作为“查询标注器(NLTKUnigramTagger)”的模型,如下例:

fd = nltk.FreqDist(brown.words(categories='news'))
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
most_freq_words = fd.keys()[:100]
likely_tags = dict((word,cfd[word].max()) for word in most_freq_words)
baseline_tagger = nltk.UnigramTagger(model=likely_tags)
baseline_tagger.evaluate(brown_tagged_sents)
# 0.005171350717027666 ?? in book it should be 0.45

此处结果与书中不同,书中结果为0.45左右,即仅仅知道100个最频繁的词的标记就能正确标注很大一部分标识符。

来看看它在未标注的输入文本是运行得怎么样:

sent = brown.sents(categories='news')[3]
baseline_tagger.tag(sent) # many words are tagged 'None',because they do not belong to 100th most used words
下面是结果:
[(u'``', None),
(u'Only', None),
(u'a', None),
(u'relative', None),
(u'handful', None),
(u'of', None),
(u'such', None),
(u'reports', u'NNS'),
(u'was', None),
(u'received', None),
(u"''", None),
(u',', None),
(u'the', None),
(u'jury', None),
(u'said', None),
(u',', None),
(u'``', None),
(u'considering', None),
(u'the', None),
(u'widespread', None),
(u'interest', None),
(u'in', None),
(u'the', None),
(u'election', None),
(u',', None),
(u'the', None),
(u'number', None),
(u'of', None),
(u'voters', None),
(u'and', None),
(u'the', None),
(u'size', None),
(u'of', None),
(u'this', None),
(u'city', None),
(u"''", None),
(u'.', None)]

可以看到很多词都被分配了'None'标签,因为它们不在100个最频繁的词中。这种情况我们想分配默认标记NN。也就是说,我们应先使用查找表,如果不能指定就使用默认标注器,这个过程叫“回退”。

baseline_tagger = nltk.UnigramTagger(model=likely_tags,backoff=nltk.DefaultTagger('NN'))


最后我们把查找标注器和默认标注器结合起来之后,看它的性能如何,使用大小不同的模型:
def performance(cfd,wordlist):
lt = dict((word,cfd[word].max()) for word in wordlist)
baseline_tagger = nltk.UnigramTagger(model=lt,backoff=nltk.DefaultTagger('NN'))
return baseline_tagger.evaluate(brown.tagged_sents(categories='news'))

def display():
import pylab
words_by_freq = list(nltk.FreqDist(brown.words(categories='news')))
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news'))
sizes = 2 ** pylab.arange(16)
prefs = [performance(cfd,words_by_freq[:size]) for size in sizes]
pylab.plot(sizes,prefs,'-bo')
pylab.title('Lookup Tagger Performance with Varying Model Size')
pylab.xlabel('Model Size')
pylab.ylabel('Performace')
pylab.show()

display()


可以看到随着模型规模的增长,最初性能增加较快,最终达到稳定水平,这时哪怕模型规模再增加,性能提升幅度也很小。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python nltk 自动标注 nlp