Extraer todos los nombres de un archivo de texto usando nltk

¿Hay una manera más eficiente de hacer esto? Mi código lee un archivo de texto y extrae todos los nombres.

import nltk File = open(fileName) #open file lines = File.read() #read all lines sentences = nltk.sent_tokenize(lines) #tokenize sentences nouns = [] #empty to array to hold all nouns for sentence in sentences: for word,pos in nltk.pos_tag(nltk.word_tokenize(str(sentence))): if (pos == 'NN' or pos == 'NNP' or pos == 'NNS' or pos == 'NNPS'): nouns.append(word) 

¿Cómo reduzco la complejidad del tiempo de este código? ¿Hay alguna manera de evitar el uso de los bucles nesteds?

¡Gracias por adelantado!

Si está abierto a otras opciones distintas de NLTK , consulte TextBlob . Extrae todos los sustantivos y frases nominales fácilmente:

 >>> from textblob import TextBlob >>> txt = """Natural language processing (NLP) is a field of computer science, artificial intelligence, and computational linguistics concerned with the inter actions between computers and human (natural) languages.""" >>> blob = TextBlob(txt) >>> print(blob.noun_phrases) [u'natural language processing', 'nlp', u'computer science', u'artificial intelligence', u'computational linguistics'] 
 import nltk lines = 'lines is some string of words' # function to test if something is a noun is_noun = lambda pos: pos[:2] == 'NN' # do the nlp stuff tokenized = nltk.word_tokenize(lines) nouns = [word for (word, pos) in nltk.pos_tag(tokenized) if is_noun(pos)] print nouns >>> ['lines', 'string', 'words'] 

Sugerencia útil: a menudo, las comprensiones de listas son un método más rápido para construir una lista que agregar elementos a una lista con el método .insert () o append (), dentro de un bucle ‘for’.

Puede lograr buenos resultados utilizando nltk , Textblob , SpaCy o cualquiera de las muchas otras bibliotecas que existen. Estas bibliotecas harán el trabajo pero con diferentes grados de eficiencia.

 import nltk from textblob import TextBlob import spacy nlp = spacy.load('en') nlp1 = spacy.load('en_core_web_lg') txt = """Natural language processing (NLP) is a field of computer science, artificial intelligence, and computational linguistics concerned with the interactions between computers and human (natural) languages.""" 

En mi Windows 10 2 cores, 4 procesadores, 8GB RAM i5 hp laptop, en una notebook jupyter, hice algunas comparaciones y aquí están los resultados.

Para TextBlob:

 %%time print([w for (w, pos) in TextBlob(txt).pos_tags if pos[0] == 'N']) 

Y la salida es

 >>> ['language', 'processing', 'NLP', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages'] Wall time: 8.01 ms #average over 20 iterations 

Para nltk:

 %%time print([word for (word, pos) in nltk.pos_tag(nltk.word_tokenize(txt)) if pos[0] == 'N']) 

Y la salida es

 >>> ['language', 'processing', 'NLP', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages'] Wall time: 7.09 ms #average over 20 iterations 

Para spacy:

 %%time print([ent.text for ent in nlp(txt) if ent.pos_ == 'NOUN']) 

Y la salida es

 >>> ['language', 'processing', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages'] Wall time: 30.19 ms #average over 20 iterations 

Parece que nltk y TextBlob son razonablemente más rápidos y esto es de esperar ya que no almacena nada más sobre el texto de entrada, txt . Spacy es mucho más lento. Una cosa más. SpaCy perdió el sustantivo NLP mientras que nltk y TextBlob lograron. Yo dispararía para nltk o TextBlob menos que haya algo más que desee extraer de la entrada txt .

Echa un vistazo a un inicio rápido en spacy aquí .
Echa un vistazo a algunos conceptos básicos sobre TextBlob aquí .
Echa un vistazo a nltk HowTos aquí

No soy un experto en PNL, pero creo que ya estás bastante cerca, y es probable que no haya una manera de mejorar la complejidad cuadrática de tiempo en estos bucles externos aquí.

Las versiones recientes de NLTK tienen una función incorporada que hace lo que está haciendo a mano, nltk.tag.pos_tag_sents , y también devuelve una lista de listas de palabras etiquetadas.

Su código no tiene redundancia: lea el archivo una vez y visite cada oración, y cada palabra etiquetada, exactamente una vez. No importa cómo escriba su código (p. Ej., Mediante el uso de comprensiones), solo ocultará los bucles nesteds, sin omitir ningún procesamiento.

El único potencial de mejora está en su complejidad de espacio: en lugar de leer todo el archivo a la vez, puede leerlo en incrementos. Pero como necesita procesar una oración completa a la vez, no es tan simple como leer y procesar una línea a la vez; así que no me molestaría a menos que tus archivos sean gigabytes completos; Para archivos cortos no va a hacer ninguna diferencia.

En resumen, tus bucles están bien. Hay una o dos cosas en tu código que puedes limpiar (por ejemplo, la cláusula if que coincide con las tags POS), pero no cambiará nada en términos de eficiencia.