Existe-t-il un moyen plus efficace de procéder? Mon code lit un fichier texte et extrait tous les noms.
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)
Comment puis-je réduire la complexité temporelle de ce code? Existe-t-il un moyen d'éviter d'utiliser les boucles imbriquées pour?
Merci d'avance!
Si vous êtes ouvert à des options autres que NLTK
, consultez TextBlob
. Il extrait facilement tous les noms et phrases nominales:
>>> 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']
Astuce utile: il arrive souvent que les compréhensions de liste soient une méthode plus rapide pour construire une liste que d'ajouter des éléments à une liste avec la méthode .insert () ou append (), dans une boucle 'for'.
Vous pouvez obtenir de bons résultats en utilisant nltk
, Textblob
, SpaCy
ou l'une des nombreuses autres bibliothèques disponibles. Ces bibliothèques feront toutes le travail mais avec différents degrés d'efficacité.
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."""
Sur mes fenêtres 10 2 cœurs, 4 processeurs, 8 Go de RAM i5 ordinateur portable hp , dans le cahier jupyter, j'ai effectué quelques comparaisons et voici les résultats.
Pour TextBlob:
%%time
print([w for (w, pos) in TextBlob(txt).pos_tags if pos[0] == 'N'])
Et la sortie est
>>> ['language', 'processing', 'NLP', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages']
Wall time: 8.01 ms #average over 20 iterations
Pour nltk:
%%time
print([Word for (Word, pos) in nltk.pos_tag(nltk.Word_tokenize(txt)) if pos[0] == 'N'])
Et la sortie est
>>> ['language', 'processing', 'NLP', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages']
Wall time: 7.09 ms #average over 20 iterations
Pour spacy:
%%time
print([ent.text for ent in nlp(txt) if ent.pos_ == 'NOUN'])
Et la sortie est
>>> ['language', 'processing', 'field', 'computer', 'science', 'intelligence', 'linguistics', 'inter', 'actions', 'computers', 'languages']
Wall time: 30.19 ms #average over 20 iterations
Il semble que nltk
et TextBlob
soient raisonnablement plus rapides et cela est normal car ne stockez rien d'autre sur le texte d'entrée, txt
. Spacy est beaucoup plus lent. Encore une chose. SpaCy
a manqué le nom NLP
tandis que nltk
et TextBlob
l'a eu. Je tirerais pour nltk
ou TextBlob
sauf s'il y a autre chose que je souhaite extraire de l'entrée txt
.
Découvrez un démarrage rapide dans spacy
ici .
Découvrez quelques notions de base sur TextBlob
ici .
Découvrez nltk
HowTos ici
Je ne suis pas un expert en PNL, mais je pense que vous êtes déjà assez proche, et il n'y a probablement aucun moyen d'améliorer la complexité temporelle quadratique dans ces boucles externes ici.
Les versions récentes de NLTK ont une fonction intégrée qui fait ce que vous faites à la main, nltk.tag.pos_tag_sents , et il retourne également une liste de listes de mots balisés.
Votre code n'a pas de redondance: vous lisez le fichier une fois et visitez chaque phrase, et chaque mot balisé, exactement une fois. Peu importe la façon dont vous écrivez votre code (par exemple, en utilisant des compréhensions), vous ne masquerez que les boucles imbriquées, sans ignorer aucun traitement.
Le seul potentiel d'amélioration réside dans la complexité de son espace: au lieu de lire l'intégralité du fichier en une seule fois, vous pouvez le lire par incréments. Mais comme vous devez traiter une phrase entière à la fois, ce n'est pas aussi simple que de lire et de traiter une ligne à la fois; donc je ne m'embêterais pas à moins que vos fichiers ne soient des gigaoctets entiers; pour les fichiers courts, cela ne fera aucune différence.
Bref, vos boucles vont bien. Il y a une ou deux choses dans votre code que vous pourriez nettoyer (par exemple la clause if
qui correspond aux balises POS), mais cela ne changera rien en termes d'efficacité.
import nltk
lines = 'lines is some string of words'
tokenized = nltk.Word_tokenize(lines)
nouns = [Word for (Word, pos) in nltk.pos_tag(tokenized) if(pos[:2] == 'NN')]
print (nouns)
Juste un peu plus.