为什么pos_tag()如此痛苦地缓慢而且可以避免这种情况?

时间:2015-11-20 14:29:31

标签: python nltk

我希望能够以这种方式逐个获得句子的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()来批量执行此操作并加快速度。但如果我可以逐句判刑,我的生活会更容易。

有没有办法更快地完成这项工作?

1 个答案:

答案 0 :(得分:16)

对于nltk 3.1版,在nltk/tag/__init__.py内,pos_tag的定义如下:

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

因此,对pos_tag的每次调用都会首先实例化PerceptronTagger,这需要一些时间,因为它涉及loading a pickle file_pos_tagtagsetNone simply calls tagger.tag。 因此,您可以通过加载文件一次来节省一些时间,并自行致电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使用与上述相同的技巧 - it instantiates PerceptronTagger once,然后多次调用_pos_tag。因此,您可以使用上述代码获得相似的性能提升,就像重构和调用pos_tag_sents一样。

此外,如果stop_words是一个长列表,您可以通过设置stop_words来节省一些时间:

stop_words = set(stop_words)

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