我一直在使用带有model关键字的NLTK Unigram标记符来传递特定标记的单词列表:
nd = dict((x,'CFN') for x in common_first_names)
...
t4 = nltk.UnigramTagger(model=nd, backoff=t3)
我希望从我的文档中提取非常具体的信息,以及具有非常不同的标点符号,大小写和语法质量的各种文档,因此使用预先存在的语料库进行培训尚未证明非常成功。我一直在做我自己的标记,如上所示,以及RegExp和Default标记符来标记我想要的东西。 我想以与上面类似的方式使用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标记的每次讨论似乎都期望训练数据,而不是模型。有没有办法用标记作为上下文标记,而不是标签?感谢
答案 0 :(得分:2)
我认为我设法提出了一个解决方案,尽管经过广泛的代码检查后这是一个猜测。我创建了自己的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)]
使用令牌上下文进行标记会在句子结尾处提供不错的结果,而使用标记上下文进行标记只能在第三个单词之前使用。