📅  最后修改于: 2020-10-14 09:23:03             🧑  作者: Mango
标记器或链接标记器彼此组合是NLTK的重要功能之一。组合标记器背后的主要概念是,如果一个标记器不知道如何标记单词,则会将其传递给链接的标记器。为了达到这个目的, SequentialBackoffTagger为我们提供了Backoff标签功能。
如前所述,回退标记是SequentialBackoffTagger的重要功能之一,它使我们能够以一种方式组合标记器,如果一个标记器不知道如何标记单词,则该单词将被传递给下一个标记器,依此类推。直到没有可供检查的退避标记器为止。
实际上, SequentialBackoffTagger的每个子类都可以使用“ backoff”关键字参数。此关键字参数的值是SequentialBackoffTagger的另一个实例。现在,无论何时初始化此SequentialBackoffTagger类,都会创建一个内部退避标记器列表(以其本身为第一个元素)。此外,如果给出了退避标记器,则将附加此退避标记器的内部列表。
在下面的示例中,我们将DefaulTagger用作上述Python配方中的退避标记器,我们已使用该配方对UnigramTagger进行了训练。
在此示例中,我们将DefaulTagger用作退避标记器。每当UnigramTagger无法标记单词时,退避标记器(即我们的DefaulTagger)将使用’NN’对其进行标记。
from nltk.tag import UnigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Uni_tagger = UnigramTagger(train_sentences, backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)
0.9061975746536931
从上面的输出中,您可以看到,通过添加退避标记器,准确性提高了约2%。
正如我们已经看到的,训练标记器非常麻烦,而且需要时间。为了节省时间,我们可以腌制经过训练的标记器,以便以后使用。在下面的示例中,我们将对已经训练有素的名为‘Uni_tagger’的标记器执行此操作。
import pickle
f = open('Uni_tagger.pickle','wb')
pickle.dump(Uni_tagger, f)
f.close()
f = open('Uni_tagger.pickle','rb')
Uni_tagger = pickle.load(f)
从以前的单元讨论的层次图,UnigramTagger从NgarmTagger类继承,但我们有两个NgarmTagger类的子类-
实际上,一个ngram是n个项目的子序列,因此,顾名思义, BigramTagger子类将查看这两个项目。第一项是先前标记的单词,第二项是当前标记的单词。
在BigramTagger的同一注释上,TrigramTagger子类查看了三个项目,即两个先前标记的单词和一个当前标记的单词。
实际上,如果像UnigramTagger子类那样单独应用BigramTagger和TrigramTagger子类,它们的性能都非常差。让我们在下面的示例中看到:
from nltk.tag import BigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Bi_tagger = BigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Bi_tagger.evaluate(test_sentences)
0.44669191071913594
from nltk.tag import TrigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Tri_tagger = TrigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Tri_tagger.evaluate(test_sentences)
0.41949863394526193
您可以将之前使用的UnigramTagger(约89%的准确性)与BigramTagger(约44%的准确性)和TrigramTagger(约41%的准确性)进行比较。原因是Bigram和Trigram标记程序无法从句子中的第一个单词学习上下文。另一方面,UnigramTagger类并不关心先前的上下文,而是猜测每个单词的最常用标签,因此能够具有较高的基线准确性。
从以上示例中可以明显看出,当将Bigram和Trigram标记器与退避标记结合使用时,它们可以发挥作用。在下面的示例中,我们将Unigram,Bigram和Trigram标记器与退避标记结合在一起。将UnigramTagger与退避标记器结合使用时,该概念与先前的配方相同。唯一的区别是,我们使用来自tagger_util.py的名为backoff_tagger()的函数(如下所示)进行后退操作。
def backoff_tagger(train_sentences, tagger_classes, backoff=None):
for cls in tagger_classes:
backoff = cls(train_sentences, backoff=backoff)
return backoff
from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(train_sentences,
[UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)
0.9234530029238365
从上面的输出中,我们可以看到它使精度提高了约3%。