web-dev-qa-db-fra.com

Suppression de mots d'arrêt avec NLTK

J'essaie de traiter un texte saisi par un utilisateur en supprimant les mots vides à l'aide de nltk toolkit, mais avec stopword-removal, les mots tels que 'et', 'ou', 'non' sont supprimés. Je veux que ces mots soient présents après le processus de suppression des mots vides, car ce sont des opérateurs requis pour le traitement ultérieur du texte en tant que requête. Je ne sais pas quels mots peuvent être des opérateurs dans une requête de texte et je souhaite également supprimer les mots inutiles de mon texte.

69
Grahesh Parkar

Je vous suggère de créer votre propre liste de mots opérateurs que vous retirez de la liste de mots vides. Les ensembles peuvent être facilement soustraits, ainsi:

operators = set(('and', 'or', 'not'))
stop = set(stopwords...) - operators

Ensuite, vous pouvez simplement tester si un mot est in ou not in l'ensemble sans que vos opérateurs fassent partie de la liste des mots vides. Vous pourrez ensuite basculer vers une autre liste de mots vides ou ajouter un opérateur.

if Word.lower() not in stop:
    # use Word
68
otus

Il existe une liste intégrée de mots vides dans NLTK composée de 2 400 mots vides pour 11 langues (Porter et al), voir http://nltk.org/book/ch02.html

>>> from nltk import Word_tokenize
>>> from nltk.corpus import stopwords
>>> stop = set(stopwords.words('english'))
>>> sentence = "this is a foo bar sentence"
>>> print([i for i in sentence.lower().split() if i not in stop])
['foo', 'bar', 'sentence']
>>> [i for i in Word_tokenize(sentence.lower()) if i not in stop] 
['foo', 'bar', 'sentence']

Je recommande de regarder avec tf-idf pour supprimer les mots vides, voir Effets de la formation de pied sur la fréquence de terme?

139
alvas

La réponse de @ alvas fait le travail mais cela peut être fait beaucoup plus rapidement. En supposant que vous ayez documents: une liste de chaînes.

from nltk.corpus import stopwords
from nltk.tokenize import wordpunct_tokenize

stop_words = set(stopwords.words('english'))
stop_words.update(['.', ',', '"', "'", '?', '!', ':', ';', '(', ')', '[', ']', '{', '}']) # remove it if you need punctuation 

for doc in documents:
    list_of_words = [i.lower() for i in wordpunct_tokenize(doc) if i.lower() not in stop_words]

Notez qu'en raison du fait que vous recherchez ici dans un ensemble (et non dans une liste), la vitesse serait théoriquement len(stop_words)/2 fois plus rapide, ce qui est significatif si vous devez utiliser plusieurs documents.

Pour 5000 documents d'environ 300 mots chacun, la différence est comprise entre 1,8 seconde pour mon exemple et 20 secondes pour @ alvas.

P.S. dans la plupart des cas, vous devez diviser le texte en mots pour effectuer d'autres tâches de classification pour lesquelles tf-idf est utilisé. Donc, il serait probablement préférable d'utiliser également stemmer:

from nltk.stem.porter import PorterStemmer
porter = PorterStemmer()

et d'utiliser [porter.stem(i.lower()) for i in wordpunct_tokenize(doc) if i.lower() not in stop_words] à l'intérieur d'une boucle.

31
Salvador Dali

@alvas a une bonne réponse. Mais là encore, cela dépend de la nature de la tâche. Par exemple, dans votre application, vous souhaitez prendre en compte tous les paramètres conjunction par exemple. et, ou, mais, si, tandis que et tous les determiner par ex. le, a, certains, la plupart, tous, aucun en tant que mots vides considérant toutes les autres parties du discours comme légitimes, alors vous voudrez peut-être examiner cette solution qui utilisent un jeu d’étiquettes de parole partielle pour supprimer des mots, voir le tableau 5.1 :

import nltk

STOP_TYPES = ['DET', 'CNJ']

text = "some data here "
tokens = nltk.pos_tag(nltk.Word_tokenize(text))
good_words = [w for w, wtype in tokens if wtype not in STOP_TYPES]
14
Aamir Adnan

Vous pouvez utiliser string.punctuation avec la liste intégrée de mots vides NLTK:

from nltk.tokenize import Word_tokenize, sent_tokenize
from nltk.corpus import stopwords
from string import punctuation

words = tokenize(text)
wordsWOStopwords = removeStopWords(words)

def tokenize(text):
        sents = sent_tokenize(text)
        return [Word_tokenize(sent) for sent in sents]

def removeStopWords(words):
        customStopWords = set(stopwords.words('english')+list(punctuation))
        return [Word for Word in words if Word not in customStopWords]

Mots finaux NLTK complets liste

6
UsmanZ