Como se livrar da pontuação usando o tokenizer NLTK?

125

Estou começando a usar o NLTK e não entendo como obter uma lista de palavras do texto. Se eu usar nltk.word_tokenize(), recebo uma lista de palavras e pontuação. Eu preciso apenas das palavras. Como posso me livrar da pontuação? Também word_tokenizenão funciona com várias frases: pontos são adicionados à última palavra.

lizarisco
fonte
12
Por que você não remove a pontuação? nltk.word_tokenize(the_text.translate(None, string.punctuation))deve funcionar em python2 enquanto em python3 você pode fazer nltk.work_tokenize(the_text.translate(dict.fromkeys(string.punctuation))).
Bakuriu 21/03/2013
3
Isso não funciona. Nada acontece com o texto.
Lizarisk 21/03
O fluxo de trabalho assumido pelo NLTK é que você primeiro tokeniza em frases e depois cada frase em palavras. É por isso word_tokenize()que não funciona com várias frases. Para se livrar da pontuação, você pode usar uma expressão regular ou a isalnum()função python .
Suzana
2
Ele faz o trabalho: >>> 'with dot.'.translate(None, string.punctuation) 'with dot'(nota sem ponto no final do resultado) Isso pode causar problemas se você tem coisas como 'end of sentence.No space', caso em que fazer isso em vez disso: the_text.translate(string.maketrans(string.punctuation, ' '*len(string.punctuation)))que substitui toda a pontuação com espaços em branco.
Bakuriu 21/03/2013
Opa, funciona mesmo, mas não com strings Unicode.
Lizarisk 21/03

Respostas:

162

Dê uma olhada nas outras opções de tokenização que o nltk fornece aqui . Por exemplo, você pode definir um tokenizador que seleciona sequências de caracteres alfanuméricos como tokens e descarta todo o resto:

from nltk.tokenize import RegexpTokenizer

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

Resultado:

['Eighty', 'seven', 'miles', 'to', 'go', 'yet', 'Onward']
rmalouf
fonte
55
Observe que, se você usar esta opção, perderá recursos de linguagem natural especiais para word_tokenizedividir contrações. Você pode dividir ingenuamente a regex \w+sem a necessidade do NLTK.
Sffc
3
Para ilustrar o comentário @sffc, você pode perder palavras como "Sr."
Geekazoid # 10/18
sua substituição 'n't' para 't' como se livrar disso?
Md. Ashikur Rahman 04/11/19
46

Você realmente não precisa do NLTK para remover a pontuação. Você pode removê-lo com python simples. Para strings:

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

Ou para unicode:

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

e use essa string no seu tokenizer.

O módulo de string PS possui alguns outros conjuntos de elementos que podem ser removidos (como dígitos).

Salvador Dalí
fonte
3
Remova toda a pontuação usando a expressão de lista que também funciona. a = "*fa,fd.1lk#$" print("".join([w for w in a if w not in string.punctuation]))
Johnny Zhang
32

O código abaixo removerá todos os sinais de pontuação e os caracteres não alfabéticos. Copiado do livro deles.

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)

resultado

['i', 'ca', 'do', 'this', 'now', 'because', 'i', 'so', 'tired', 'please', 'give', 'me', 'some', 'time', 'sd']
Madura Pradeep
fonte
17
Lembre-se de que, usando esse método, você perderá a palavra "não" em casos como "não pode" ou "não", que podem ser muito importantes para entender e classificar a frase. É melhor usar o frase.translate (string.maketrans ("", "",), chars_to_remove)), onde chars_to_remove pode ser "., ':;!?"
27617
3
@MikeL Você não pode contornar palavras como "não pode" e "não" importando contrações e contractions.fix (frase_aqui) antes de iniciar o processo. Ele transformará "não pode" em "não pode" e "não" em "não".
zipline86
16

Conforme observado nos comentários, comece com sent_tokenize (), porque o word_tokenize () funciona apenas em uma única frase. Você pode filtrar a pontuação com filter (). E se você tiver uma string unicode, verifique se é um objeto unicode (não uma 'str' codificada com alguma codificação como '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
fonte
14
A maior parte da complexidade envolvida no tokenizador Penn Treebank tem a ver com o manuseio adequado da pontuação. Por que usar um tokenizador caro que lida bem com a pontuação, se você deseja apenas remover a pontuação?
Rmalouf
3
word_tokenizeé uma função que retorna [token for sent in sent_tokenize(text, language) for token in _treebank_word_tokenize(sent)]. Então, acho que sua resposta está fazendo o que o nltk já faz: usando sent_tokenize()antes de usar word_tokenize(). Pelo menos isso é para nltk3.
Kurt Bourbaki
2
@rmalouf porque você não precisa de tokens apenas de pontuação? Então você quer dide n'tnão.
Ciprian Tomoiagă
11

Acabei de usar o código a seguir, que removeu toda a pontuação:

tokens = nltk.wordpunct_tokenize(raw)

type(tokens)

text = nltk.Text(tokens)

type(text)  

words = [w.lower() for w in text if w.isalpha()]
vish
fonte
2
por que converter tokens em texto?
Sadik
6

Eu acho que você precisa de algum tipo de correspondência de expressão regular (o código a seguir está no 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)

Resultado:

['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']

Na maioria dos casos, deve funcionar bem, pois remove a pontuação e preserva tokens como "n't", que não podem ser obtidos em tokenizadores de regex, como wordpunct_tokenize.

Quan Gan
fonte
Isso também irá remover coisas como ...e --quando as contrações preservando, que s.translate(None, string.punctuation)não vai
CJ Jackson
5

Sinceramente perguntando, o que é uma palavra? Se você pressupõe que uma palavra consiste apenas em caracteres alfabéticos, você está errado, pois palavras como can'tserão destruídas em pedaços (como cane t) se você remover a pontuação antes da tokenização , o que provavelmente afetará negativamente o seu programa.

Portanto, a solução é tokenizar e remover os tokens de pontuação .

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']

... e, se desejar, você pode substituir certos tokens, como 'mpor am.

Bora M. Alper
fonte
4

Eu uso esse código para remover a pontuação:

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 ")

E se você quiser verificar se um token é uma palavra válida em inglês ou não, pode ser necessário o PyEnchant

Tutorial:

 import enchant
 d = enchant.Dict("en_US")
 d.check("Hello")
 d.check("Helo")
 d.suggest("Helo")
zhenv5
fonte
2
Cuidado que esta solução mata contrações. Isso é porque word_tokenizeuso o tokenizer padrão, TreebankWordTokenizer, que divide as contrações (por exemplo, can'ta ( ca, n't) No entanto. n'tNão é alfanumérico e se perder no processo.
Diego Ferri
1

Remover pontuação (isso removerá., Bem como parte do tratamento da pontuação usando o código abaixo)

        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 

Entrada / Saída de amostra:

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
fonte
Muito obrigado
1

Apenas adicionando à solução por @rmalouf, isso não incluirá nenhum número porque \ w + é equivalente a [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
fonte
Este cria um token para cada letra.
Rishabh Gupta 17/03
1

Você pode fazer isso em uma linha sem o nltk (python 3.x).

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