【问题标题】:Fast Named Entity Removal with NLTK使用 NLTK 快速删除命名实体
【发布时间】:2017-05-03 21:42:44
【问题描述】:

我编写了几个用户定义的函数来从文本句子/段落列表中删除 Python 中的命名实体(使用 NLTK)。我遇到的问题是我的方法非常慢,尤其是对于大量数据。有没有人建议如何优化它以使其运行得更快?

import nltk
import string

# Function to reverse tokenization
def untokenize(tokens):
    return("".join([" "+i if not i.startswith("'") and i not in string.punctuation else i for i in tokens]).strip())

# Remove named entities
def ne_removal(text):
    tokens = nltk.word_tokenize(text)
    chunked = nltk.ne_chunk(nltk.pos_tag(tokens))
    tokens = [leaf[0] for leaf in chunked if type(leaf) != nltk.Tree]
    return(untokenize(tokens))

要使用代码,我通常有一个文本列表并通过列表理解调用ne_removal 函数。示例如下:

text_list = ["Bob Smith went to the store.", "Jane Doe is my friend."]
named_entities_removed = [ne_removal(text) for text in text_list]
print(named_entities_removed)
## OUT: ['went to the store.', 'is my friend.']

更新:我尝试使用此代码切换到批处理版本,但它只是稍微快一点。会继续探索。感谢您迄今为止的意见。

def extract_nonentities(tree):
    tokens = [leaf[0] for leaf in tree if type(leaf) != nltk.Tree]
    return(untokenize(tokens))

def fast_ne_removal(text_list):
    token_list = [nltk.word_tokenize(text) for text in text_list]
    tagged = nltk.pos_tag_sents(token_list)
    chunked = nltk.ne_chunk_sents(tagged)
    non_entities = []
    for tree in chunked:
        non_entities.append(extract_nonentities(tree))
    return(non_entities)

【问题讨论】:

  • 我不确定迁移到 codereview 是否合适。过慢的代码一个问题,这不是关于“我可以更好地构建我的代码吗”。

标签: python optimization nltk named-entity-recognition


【解决方案1】:

每次调用ne_chunk(),它都需要初始化一个chunker对象,并从磁盘加载用于分块的统计模型。 pos_tag() 同上。所以不要一次只用一个句子来调用它们,而是在完整的文本列表中调用它们的批处理版本:

all_data = [ nltk.word_tokenize(sent) for sent in list_of_all_sents ]
tagged = nltk.pos_tag_sents(all_data)
chunked = nltk.ne_chunk_sents(tagged)

这应该会给你一个相当大的加速。如果这对您的需求来说仍然太慢,请尝试分析您的代码并考虑是否需要切换到功能更强大的工具,如 @Lenz 建议的那样。

【讨论】:

  • 另外,测试i not in string.punctuation 通过搜索字符串查找i。用一个集合(全局定义)替换string.punctuation 将大大加快这条线的速度——不过,我无法预测这是否是总运行时间的重要部分,因为标记和分块更耗时。跨度>
  • 谢谢!我正在玩批处理版本(代码添加到原始帖子)。我在 1,000 个句子上计时,它的速度稍快(78.9 秒,而旧方法为 82.5 秒),但并不显着。我可能会探索使用 spaCy 的命名实体标记器作为加快速度的更简单方法。我也会先尝试 string.punctuation 更改。
  • 听到这个我有点惊讶;它应该有很大的不同,除非你的代码有问题。但是,在您彻底分析当前代码并了解时间的去向之前,不要浪费时间安装其他标记器。确保这不是愚蠢的事情,例如对主要数据的低效管理。
猜你喜欢
  • 2013-10-19
  • 1970-01-01
  • 2020-02-01
  • 2012-07-02
  • 2014-08-15
  • 2020-04-06
  • 2019-03-14
  • 2015-10-28
  • 2020-11-28
相关资源
最近更新 更多