Python 用NLTK快速删除命名实体

Python 用NLTK快速删除命名实体,python,optimization,nltk,named-entity-recognition,Python,Optimization,Nltk,Named Entity Recognition,我编写了两个用户定义的函数来从文本句子/段落列表中删除Python中的命名实体(使用NLTK)。我遇到的问题是,我的方法非常慢,尤其是对于大量数据。有人对如何优化它以使其运行更快有什么建议吗 import nltk import string # Function to reverse tokenization def untokenize(tokens): return("".join([" "+i if not i.startswith("'") and i not in stri

我编写了两个用户定义的函数来从文本句子/段落列表中删除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_remove
函数。示例如下:

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)

每次调用
ne_chunk()
,它都需要初始化chunker对象并从磁盘加载用于分块的统计模型。
pos\u 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)

这会给你一个相当大的加速。如果这对你的需求来说还是太慢,试着分析你的代码,考虑你是否需要切换到更高性能的工具,比如@ Lez建议。

我不确定迁移到CoDeVIEW是合适的。代码速度过慢是一个问题,这与“我可以更好地构建代码”无关。此外,测试
I不在字符串中。标点符号
通过搜索字符串来查找
I
。将
字符串.标点符号
替换为一个集合(全局定义)将大大加快这一行的速度--尽管如此,我无法预测这是否是整个运行时的重要部分,因为标记和分块要耗时得多.谢谢!我正在玩批处理版本(代码添加到原始帖子中)。我用1000句话来计时,速度稍微快一些(78.9秒,旧方法是82.5秒),但并不显著。我可能会探索使用spaCy的命名实体标记器作为一种更简单的加速方式。我会先试试
字符串。标点符号也会改变。听到这个我有点惊讶;除非你的代码有什么问题,否则它应该会有很大的不同。但是不要浪费时间安装其他标记器,除非您已经完全分析了当前代码并了解时间的走向。例如,确保它不是像对主数据的低效管理这样愚蠢的事情。