Comment se débarrasser de la ponctuation à l'aide du tokenizer NLTK?

125

Je commence tout juste à utiliser NLTK et je ne comprends pas très bien comment obtenir une liste de mots à partir d'un texte. Si j'utilise nltk.word_tokenize(), j'obtiens une liste de mots et de ponctuation. Je n'ai besoin que des mots à la place. Comment puis-je me débarrasser de la ponctuation? Aussi word_tokenizene fonctionne pas avec plusieurs phrases: points sont ajoutés au dernier mot.

lizarisk
la source
12
Pourquoi ne supprimez-vous pas vous-même la ponctuation? nltk.word_tokenize(the_text.translate(None, string.punctuation))devrait fonctionner en python2 alors qu'en python3 vous pouvez le faire nltk.work_tokenize(the_text.translate(dict.fromkeys(string.punctuation))).
Bakuriu
3
Cela ne marche pas. Rien ne se passe avec le texte.
lizarisk
Le flux de travail supposé par NLTK est que vous commencez par tokenize en phrases, puis chaque phrase en mots. C'est pourquoi word_tokenize()ne fonctionne pas avec plusieurs phrases. Pour vous débarrasser de la ponctuation, vous pouvez utiliser une expression régulière ou une isalnum()fonction de python .
Suzana
2
Il fait le travail: >>> 'with dot.'.translate(None, string.punctuation) 'with dot'(note dot pas à la fin du résultat) Il peut causer des problèmes si vous avez des choses comme 'end of sentence.No space', dans ce cas , faire à la place: the_text.translate(string.maketrans(string.punctuation, ' '*len(string.punctuation)))qui remplace la ponctuation par des espaces blancs.
Bakuriu
Oups, cela fonctionne en effet, mais pas avec les chaînes Unicode.
lizarisk

Réponses:

162

Jetez un œil aux autres options de tokenisation fournies par nltk ici . Par exemple, vous pouvez définir un tokenizer qui sélectionne des séquences de caractères alphanumériques comme jetons et supprime tout le reste:

from nltk.tokenize import RegexpTokenizer

tokenizer = RegexpTokenizer(r'\w+')
tokenizer.tokenize('Eighty-seven miles to go, yet.  Onward!')

Production:

['Eighty', 'seven', 'miles', 'to', 'go', 'yet', 'Onward']
rmalouf
la source
55
Notez que si vous utilisez cette option, vous perdez les fonctionnalités du langage naturel spéciales word_tokenizecomme la séparation des contractions. Vous pouvez diviser naïvement sur l'expression \w+régulière sans avoir besoin du NLTK.
sffc
3
Pour illustrer le commentaire @sffc, vous risquez de perdre des mots tels que "M."
geekazoid
son remplacement «n't» à «t» comment se débarrasser de cela?
Md. Ashikur Rahman
46

Vous n'avez pas vraiment besoin de NLTK pour supprimer la ponctuation. Vous pouvez le supprimer avec un simple python. Pour les chaînes:

import string
s = '... some string with punctuation ...'
s = s.translate(None, string.punctuation)

Ou pour unicode:

import string
translate_table = dict((ord(char), None) for char in string.punctuation)   
s.translate(translate_table)

puis utilisez cette chaîne dans votre tokenizer.

Le module de chaîne PS a d'autres ensembles d'éléments qui peuvent être supprimés (comme des chiffres).

Salvador Dali
la source
3
Supprimez toute ponctuation à l'aide de l'expression de liste qui fonctionne également. a = "*fa,fd.1lk#$" print("".join([w for w in a if w not in string.punctuation]))
Johnny Zhang
32

Le code ci-dessous supprimera tous les signes de ponctuation ainsi que les caractères non alphabétiques. Copié de leur livre.

http://www.nltk.org/book/ch01.html

import nltk

s = "I can't do this now, because I'm so tired.  Please give me some time. @ sd  4 232"

words = nltk.word_tokenize(s)

words=[word.lower() for word in words if word.isalpha()]

print(words)

production

['i', 'ca', 'do', 'this', 'now', 'because', 'i', 'so', 'tired', 'please', 'give', 'me', 'some', 'time', 'sd']
Madura Pradeep
la source
17
Sachez simplement qu'en utilisant cette méthode, vous perdrez le mot «pas» dans des cas comme «ne peut pas» ou «ne pas», ce qui peut être très important pour comprendre et classer la phrase. Il est préférable d'utiliser sentence.translate (string.maketrans ("", "",), chars_to_remove), où chars_to_remove peut être "., ':;!?"
MikeL
3
@MikeL Vous ne pouvez pas contourner des mots comme «ne peut pas» et «ne pas» en important des contractions et contractions.fix (phrase_ici) avant de tokaniser. Il transformera "ne peut pas" en "ne peut pas" et "ne pas" en "ne pas".
tyrolienne86
16

Comme remarqué dans les commentaires, commencez par sent_tokenize (), car word_tokenize () ne fonctionne que sur une seule phrase. Vous pouvez filtrer la ponctuation avec filter (). Et si vous avez une chaîne Unicode, assurez-vous que c'est un objet Unicode (pas un 'str' encodé avec un encodage comme 'utf-8').

from nltk.tokenize import word_tokenize, sent_tokenize

text = '''It is a blue, small, and extraordinary ball. Like no other'''
tokens = [word for sent in sent_tokenize(text) for word in word_tokenize(sent)]
print filter(lambda word: word not in ',-', tokens)
palooh
la source
14
La plupart de la complexité impliquée dans le tokenizer Penn Treebank est liée à la bonne gestion de la ponctuation. Pourquoi utiliser un tokenizer coûteux qui gère bien la ponctuation si vous ne comptez supprimer que la ponctuation?
rmalouf
3
word_tokenizeest une fonction qui retourne [token for sent in sent_tokenize(text, language) for token in _treebank_word_tokenize(sent)]. Donc, je pense que votre réponse fait ce que nltk fait déjà: utiliser sent_tokenize()avant d'utiliser word_tokenize(). Au moins, c'est pour nltk3.
Kurt Bourbaki
2
@rmalouf parce que vous n'avez pas besoin de jetons de ponctuation uniquement? Alors vous voulez didet n'tmais pas.
Ciprian Tomoiagă
11

Je viens d'utiliser le code suivant, qui a supprimé toute la ponctuation:

tokens = nltk.wordpunct_tokenize(raw)

type(tokens)

text = nltk.Text(tokens)

type(text)  

words = [w.lower() for w in text if w.isalpha()]
vish
la source
2
pourquoi convertir des jetons en texte?
Sadik
6

Je pense que vous avez besoin d'une sorte de correspondance d'expression régulière (le code suivant est en Python 3):

import string
import re
import nltk

s = "I can't do this now, because I'm so tired.  Please give me some time."
l = nltk.word_tokenize(s)
ll = [x for x in l if not re.fullmatch('[' + string.punctuation + ']+', x)]
print(l)
print(ll)

Production:

['I', 'ca', "n't", 'do', 'this', 'now', ',', 'because', 'I', "'m", 'so', 'tired', '.', 'Please', 'give', 'me', 'some', 'time', '.']
['I', 'ca', "n't", 'do', 'this', 'now', 'because', 'I', "'m", 'so', 'tired', 'Please', 'give', 'me', 'some', 'time']

Cela devrait bien fonctionner dans la plupart des cas, car il supprime la ponctuation tout en préservant les jetons comme "n't", qui ne peuvent pas être obtenus à partir de jetons de regex tels que wordpunct_tokenize.

Quan Gan
la source
Cela supprimera également des choses comme ...et --tout en préservant les contractions, ce s.translate(None, string.punctuation)qui ne le fera pas
CJ Jackson
5

En demandant sincèrement, qu'est-ce qu'un mot? Si vous supposez qu'un mot est composé uniquement de caractères alphabétiques, vous vous trompez car des mots tels que can'tseront détruits en morceaux (tels que canet t) si vous supprimez la ponctuation avant la tokenisation , ce qui est très susceptible d'affecter négativement votre programme.

Par conséquent, la solution est de tokeniser puis de supprimer les jetons de ponctuation .

import string

from nltk.tokenize import word_tokenize

tokens = word_tokenize("I'm a southern salesman.")
# ['I', "'m", 'a', 'southern', 'salesman', '.']

tokens = list(filter(lambda token: token not in string.punctuation, tokens))
# ['I', "'m", 'a', 'southern', 'salesman']

... et ensuite si vous le souhaitez, vous pouvez remplacer certains jetons tels que 'mpar am.

Bora M. Alper
la source
4

J'utilise ce code pour supprimer la ponctuation:

import nltk
def getTerms(sentences):
    tokens = nltk.word_tokenize(sentences)
    words = [w.lower() for w in tokens if w.isalnum()]
    print tokens
    print words

getTerms("hh, hh3h. wo shi 2 4 A . fdffdf. A&&B ")

Et si vous voulez vérifier si un jeton est un mot anglais valide ou non, vous aurez peut-être besoin de PyEnchant

Didacticiel:

 import enchant
 d = enchant.Dict("en_US")
 d.check("Hello")
 d.check("Helo")
 d.suggest("Helo")
zhenv5
la source
2
Attention, cette solution tue les contractions. En effet, word_tokenizeutilisez le tokenizer standard,, TreebankWordTokenizerqui divise les contractions (par exemple can'ten ( ca, n't). Cependant, ce n'tn'est pas alphanumérique et perdez-vous dans le processus.
Diego Ferri
1

Supprimer la ponctuation (elle supprimera. Ainsi qu'une partie de la gestion de la ponctuation en utilisant le code ci-dessous)

        tbl = dict.fromkeys(i for i in range(sys.maxunicode) if unicodedata.category(chr(i)).startswith('P'))
        text_string = text_string.translate(tbl) #text_string don't have punctuation
        w = word_tokenize(text_string)  #now tokenize the string 

Exemple d'entrée / sortie:

direct flat in oberoi esquire. 3 bhk 2195 saleable 1330 carpet. rate of 14500 final plus 1% floor rise. tax approx 9% only. flat cost with parking 3.89 cr plus taxes plus possession charger. middle floor. north door. arey and oberoi woods facing. 53% paymemt due. 1% transfer charge with buyer. total cost around 4.20 cr approx plus possession charges. rahul soni

['direct', 'flat', 'oberoi', 'esquire', '3', 'bhk', '2195', 'saleable', '1330', 'carpet', 'rate', '14500', 'final', 'plus', '1', 'floor', 'rise', 'tax', 'approx', '9', 'flat', 'cost', 'parking', '389', 'cr', 'plus', 'taxes', 'plus', 'possession', 'charger', 'middle', 'floor', 'north', 'door', 'arey', 'oberoi', 'woods', 'facing', '53', 'paymemt', 'due', '1', 'transfer', 'charge', 'buyer', 'total', 'cost', 'around', '420', 'cr', 'approx', 'plus', 'possession', 'charges', 'rahul', 'soni']

ascii_walker
la source
Merci beaucoup
1

En ajoutant simplement à la solution de @rmalouf, cela n'inclura aucun nombre car \ w + équivaut à [a-zA-Z0-9_]

from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer(r'[a-zA-Z]')
tokenizer.tokenize('Eighty-seven miles to go, yet.  Onward!')
Himanshu Aggarwal
la source
Celui-ci crée un jeton pour chaque lettre.
Rishabh Gupta
1

Vous pouvez le faire en une seule ligne sans nltk (python 3.x).

import string
string_text= string_text.translate(str.maketrans('','',string.punctuation))
Nishān Wickramarathna
la source