nltk自定义分词器和标注器

3 投票
2 回答
4696 浏览
提问于 2025-04-16 05:28

这是我的需求。我想对一段文字进行分词和标记,目的是为了实现以下几点。

  • 能够识别段落中的日期和时间,并将它们标记为 DATE 和 TIME
  • 能够识别段落中的已知短语,并将它们标记为 CUSTOM
  • 其余的内容应该使用默认的 nltk 库中的 word_tokenize 和 pos_tag 函数进行分词和标记。

举个例子,以下句子

"They all like to go there on 5th November 2010, but I am not interested."

在这个例子中,如果自定义短语是 "我不感兴趣",那么应该被标记和分词成这样。

[('They', 'PRP'), ('all', 'VBP'), ('like', 'IN'), ('to', 'TO'), ('go', 'VB'), 
('there', 'RB'), ('on', 'IN'), ('5th November 2010', 'DATE'), (',', ','), 
('but', 'CC'), ('I am not interested', 'CUSTOM'), ('.', '.')]

任何建议都很有帮助。

2 个回答

2

你可能需要使用nltk库里的RegexpParser来进行分块处理,这样才能达到你的目标。

参考链接: http://nltk.googlecode.com/svn/trunk/doc/book/ch07.html#code-chunker1

7

正确的做法是先准备一个标记好的大数据集,然后用这个数据集来训练一个机器学习的分块器。如果觉得这样太耗时间,简单的方法就是先运行一个词性标注器,然后用正则表达式对它的输出结果进行后处理。这里最难的部分是找到最长的匹配:

s = "They all like to go there on 5th November 2010, but I am not interested."

DATE = re.compile(r'^[1-9][0-9]?(th|st|rd)? (January|...)( [12][0-9][0-9][0-9])?$')

def custom_tagger(sentence):
    tagged = pos_tag(word_tokenize(sentence))
    phrase = []
    date_found = False

    i = 0
    while i < len(tagged):
        (w,t) = tagged[i]
        phrase.append(w)
        in_date = DATE.match(' '.join(phrase))
        date_found |= bool(in_date)
        if date_found and not in_date:          # end of date found
            yield (' '.join(phrase[:-1]), 'DATE')
            phrase = []
            date_found = False
        elif date_found and i == len(tagged)-1:    # end of date found
            yield (' '.join(phrase), 'DATE')
            return
        else:
            i += 1
            if not in_date:
                yield (w,t)
                phrase = []

待办事项:扩展 DATE 的正则表达式,添加代码来搜索 CUSTOM 短语,通过匹配词性标签和词元来让这个过程更复杂,并决定像 5th 这样的单独数字是否应该算作日期。(可能不算,所以要过滤掉只包含序数的长度为一的日期。)

撰写回答