【问题标题】:Python NLTK Ngram tagger with token context, rather than tag context带有标记上下文的 Python NLTK Ngram 标记器,而不是标记上下文
【发布时间】:2014-12-31 14:24:43
【问题描述】:

我一直在使用带有 model 关键字的 NLTK Unigram 标记器来传递特定标记的单词列表:

nd = dict((x,'CFN') for x in common_first_names)
...
t4 = nltk.UnigramTagger(model=nd, backoff=t3)

我有非常具体的信息要从我的文档中提取,以及各种标点符号、大写字母和语法质量非常不同的文档,因此使用预先存在的语料库进行训练并不是很成功。如上所示,我一直在做自己的标记,以及正则表达式和默认标记器,以完全按照我的意愿标记事物。 我想以与上述类似的方式使用 Bigram 和 Trigram 标记器,传入一个单词组合模型,以便根据它前面的单词对序列中的最后一个单词进行标记,例如:

# 'the' gets different tag depending on preceding word
{
('for','the') : 'FT',  
('into','the') : 'IT',
('on','the') : 'OT'
}

但我发现 Ngram 标注器使用标签而不是标记来表示左侧上下文是一个艰难的过程(代码阅读、调试,然后最终重新阅读清楚说明的书)。由于“for”、“into”和“on”可能都以相同的方式标记,因此我无法区分它们。此外,对标签的依赖使得 Ngram 标注器总体上毫无用处,除非你有一个大型且相关的训练集,因为它们一旦看到未标记的单词或以不在训练数据中的方式标记的单词就会中断。

我进行了大量搜索,但在任何地方都没有找到任何关于此的讨论。除了 Unigram 标注器之外,每一次对 Ngram 标注器的讨论似乎都期待训练数据,而不是模型。有没有办法用标记作为上下文而不是标签?谢谢

【问题讨论】:

    标签: python nltk n-gram


    【解决方案1】:

    我想我设法想出了一个解决方案,尽管这是经过大量代码检查后的猜测。我创建了自己的 Ngram 标记器作为 NLTK NgramTagger 类的子类,如下所示:

    class myNgramTagger(nltk.NgramTagger):
        """
        My override of the NLTK NgramTagger class that considers previous
        tokens rather than previous tags for context.
        """
        def __init__(self, n, train=None, model=None,
                     backoff=None, cutoff=0, verbose=False):
            nltk.NgramTagger.__init__(self, n, train, model, backoff, cutoff, verbose)
    
        def context(self, tokens, index, history):
            #tag_context = tuple(history[max(0,index-self._n+1):index])
            tag_context = tuple(tokens[max(0,index-self._n+1):index])
            return tag_context, tokens[index]
    

    我唯一更改的行是上下文方法中的注释行,我将历史列表更改为标记列表。我几乎只是猜测这可能会达到我想要的效果,但它似乎适用于模型和训练数据。

    test_sent = ["When","a","small","plane","crashed","into","the","river","a","general","alert","was","a","given"]
    
    tm2 = {
        (('When',), 'a') : "XX",
        (('into',), 'the') : "YY",
    }
    
    tm3 = {
        (('a','general'), 'alert') : "ZZ",
    }
    
    taggerd = nltk.DefaultTagger('NA')
    tagger2w = myNgramTagger(2,model=tm2,backoff=taggerd)
    tagger3w = myNgramTagger(3,model=tm3,backoff=tagger2w)
    print tagger3w.tag(test_sent)
    
    [('When', 'NA'), ('a', 'XX'), ('small', 'NA'), ('plane', 'NA'), ('crashed', 'NA'), ('into', 'NA'), ('the', 'YY'), ('river', 'NA'), ('a', 'NA'), ('general', 'NA'), ('alert', 'ZZ'), ('was', 'NA'), ('a', 'NA'), ('given', 'NA')]
    

    因此,仅通过在一种方法中更改一个单词,我似乎已经设法得到我想要的,使用标记作为上下文而不是标签的 Ngram 标记。

    我尝试使用带有新闻类别的棕色语料库进行类似的训练(因此我选择了测试句),它似乎工作得很好,实际上比使用标签更好,因为它设法标记句子中的所有内容识别,而不是在看到它不识别的东西时停下来:

    from nltk.corpus import brown
    brown_tagged_sents = brown.tagged_sents(categories='news')
    brown_tagger_bigram = myNgramTagger(2,brown_tagged_sents)
    brown_tagger_trigram = myNgramTagger(3,brown_tagged_sents,backoff=brown_tagger_bigram)
    print brown_tagger_trigram.tag(test_sent)
    
    [('When', u'WRB'), ('a', u'AT'), ('small', u'JJ'), ('plane', None), ('crashed', None), ('into', None), ('the', u'AT'), ('river', None), ('a', None), ('general', u'JJ'), ('alert', None), ('was', None), ('a', u'AT'), ('given', u'VBN')]
    

    将此与普通的 NLTK Ngram 标记器进行比较实际上表明这是一个改进:

    from nltk.corpus import brown
    brown_tagged_sents = brown.tagged_sents(categories='news')
    brown_tagger_bigram = nltk.NgramTagger(2,brown_tagged_sents)
    brown_tagger_trigram = nltk.NgramTagger(3,brown_tagged_sents,backoff=brown_tagger_bigram)
    print brown_tagger_trigram.tag(test_sent)
    
    [('When', u'WRB'), ('a', u'AT'), ('small', u'JJ'), ('plane', None), ('crashed', None), ('into', None), ('the', None), ('river', None), ('a', None), ('general', None), ('alert', None), ('was', None), ('a', None), ('given', None)]
    

    使用标记上下文进行标记可以一直到句子的结尾都给出不错的结果,而使用标记上下文进行标记只能到第三个单词为止。

    【讨论】:

      猜你喜欢
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-07
      • 2016-01-09
      • 2015-06-06
      • 2011-04-25
      相关资源
      最近更新 更多