一尘不染

为什么pos_tag()如此缓慢,却可以避免?

python

我希望能够以这种方式一个接一个地获取句子的POS标签:

def __remove_stop_words(self, tokenized_text, stop_words):

    sentences_pos = nltk.pos_tag(tokenized_text)  
    filtered_words = [word for (word, pos) in sentences_pos 
                      if pos not in stop_words and word not in stop_words]

    return filtered_words

但是问题是pos_tag()每个句子大约需要一秒钟。还有另一种选择可用于pos_tag_sents()批量执行此操作并加快处理速度。但是,如果我能逐句地做这件事,我的生活会更轻松。

有没有办法更快地做到这一点?


阅读 268

收藏
2021-01-20

共1个答案

一尘不染

对于NLTK
3.1版,里面nltk/tag/__init__.pypos_tag是这样定义的:

from nltk.tag.perceptron import PerceptronTagger
def pos_tag(tokens, tagset=None):
    tagger = PerceptronTagger()
    return _pos_tag(tokens, tagset, tagger)

因此,每次对pos_tagfirst的调用实例化PerceptronTagger都会花费一些时间,因为它涉及加载pickle文件_pos_tag
只需调用tagger.tagwhentagsetNone。因此,您可以通过
一次 加载文件并调用tagger.tag自己而不是调用来节省一些时间pos_tag

from nltk.tag.perceptron import PerceptronTagger
tagger = PerceptronTagger() 
def __remove_stop_words(self, tokenized_text, stop_words, tagger=tagger):
    sentences_pos = tagger.tag(tokenized_text)  
    filtered_words = [word for (word, pos) in sentences_pos 
                      if pos not in stop_words and word not in stop_words]

    return filtered_words

pos_tag_sents使用与上述相同的技巧-实例化PerceptronTagger一次,然后调用_pos_tag多次。因此,使用上述代码,您将获得与重构和调用相当的性能提升pos_tag_sents


另外,如果stop_words列表很长,则可以通过stop_words设置以下设置节省一些时间:

stop_words = set(stop_words)

因为检查集合中的成员资格(例如pos not in stop_words)是一项O(1)(恒定时间)操作,而检查列表中的成员资格是一项O(n)操作(即,它需要的时间与列表的长度成比例地增加)。

2021-01-20