¿Por qué pos_tag () es tan dolorosamente lento y esto puede evitarse?

Quiero poder obtener tags POS de las frases una por una, de esta manera:

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 

Pero el problema es que pos_tag() toma aproximadamente un segundo para cada oración. Hay otra opción para usar pos_tag_sents() para hacer esto por lotes y acelerar las cosas. Pero mi vida sería más fácil si pudiera hacer esta oración por oración.

¿Hay una manera de hacerlo más rápido?

Para nltk versión 3.1, dentro de nltk/tag/__init__.py , pos_tag se define así:

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

Por lo tanto, cada llamada a pos_tag instancia de PerceptronTagger que lleva algún tiempo porque implica cargar un archivo pickle . _pos_tag simplemente llama a tagger.tag cuando tagger.tag es None . Así que puedes ahorrar algo de tiempo cargando el archivo una vez y llamando a tagger.tag lugar de llamar a 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 utiliza el mismo truco que el anterior: _pos_tag una instancia de PerceptronTagger una vez antes de llamar a _pos_tag muchas veces. Por lo tanto, obtendrá un aumento de rendimiento comparable con el código anterior como lo haría refactorizando y llamando a pos_tag_sents .


Además, si stop_words es una lista larga, puede ahorrar un poco de tiempo al hacer que stop_words un conjunto:

 stop_words = set(stop_words) 

ya que verificar la membresía en un conjunto (por ejemplo, pos not in stop_words ) es una pos not in stop_words O(1) (tiempo constante), mientras que la verificación de la membresía en una lista es una operación O(n) (es decir, requiere un tiempo que crece proporcionalmente a la longitud del lista.)