2015-11-20 16 views
5

Voglio essere in grado di ottenere POS-Tag di frasi ad una ad una come in questo modo:Perché pos_tag() è così dolorosamente lento e può essere evitato?

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 

Ma il problema è che pos_tag() dura circa un secondo per ogni frase. C'è un'altra opzione per usare pos_tag_sents() per fare questo batch-saggio e accelerare le cose. Ma la mia vita sarebbe più facile se potessi fare questa frase per frase.

C'è un modo per farlo più velocemente?

+0

Quale versione di nltk stai usando? (ad esempio 'nltk .__ version__') – unutbu

+0

è 3.1 (asdfasdf) – displayname

+0

Background: http://stackoverflow.com/questions/33676526/pos-tagger-is-incredibly-slow#comment55128218_33677051 – tripleee

risposta

14

Per NLTK versione 3.1, all'interno nltk/tag/__init__.py, pos_tag si definisce in questo modo:

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

Così ogni chiamata al pos_tag prima crea un'istanza PerceptronTagger che richiede un po 'di tempo perché si tratta di loading a pickle file. _pos_tagsimply calls tagger.tag quando tagset è None. in modo da poter risparmiare un po 'di tempo caricando il file volta, e chiamando tagger.tag te stesso invece di chiamare 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 utilizza lo stesso trucco come sopra - it instantiates PerceptronTagger once prima di chiamare _pos_tag molte volte. In questo modo otterrai un guadagno comparabile in termini di prestazioni utilizzando il codice sopra riportato, come faresti con il refactoring e chiamando lo pos_tag_sents.


Inoltre, se stop_words è una lunga lista, è possibile salvare un po 'di tempo facendo stop_words un set:

stop_words = set(stop_words) 

dal check appartenenza a un gruppo (ad es pos not in stop_words) è un O(1) (l'ora costante) mentre si controlla l'appartenenza a un elenco è un'operazione O(n) (cioè richiede tempo che cresce proporzionalmente alla lunghezza dell'elenco.)

+0

Ora, questo è ciò di cui sto parlando! È strano pensare che devo farlo in questo modo. Voglio dire, quanto spesso capita che qualcuno voglia semplicemente taggare * una * singola frase? Sarebbe interessante sapere perché gli sviluppatori hanno deciso che questa è una buona idea, ma sono felice di avere una soluzione alternativa. Grazie! – displayname

+1

Bene, 'pos_tag()' è una funzione. Se chiami una funzione ti aspetti che dopo che la funzione è stata eseguita ottieni un risultato e nulla rimane in memoria. – thorsten

+3

@StefanFalk, 'pos_tag' è pensato per essere un tipo di anatra. E parte del motivo per mantenerlo è per la compatibilità con NLTK <3.1. Usa sempre il tagger specifico quando possibile. =) – alvas

Problemi correlati