Jak pozbyć się interpunkcji za pomocą tokenizera NLTK?


125

Dopiero zaczynam używać NLTK i nie do końca rozumiem, jak uzyskać listę słów z tekstu. Jeśli używam nltk.word_tokenize(), otrzymuję listę słów i znaków interpunkcyjnych. Zamiast tego potrzebuję tylko słów. Jak pozbyć się interpunkcji? Również word_tokenizenie działa z wieloma zdaniami: punkty są dodawane do ostatniego słowa.


12
Dlaczego sam nie usuniesz interpunkcji? nltk.word_tokenize(the_text.translate(None, string.punctuation))powinien działać w python2, podczas gdy w python3 możesz to zrobić nltk.work_tokenize(the_text.translate(dict.fromkeys(string.punctuation))).
Bakuriu

3
To nie działa. Nic się nie dzieje z tekstem.
lizarisk

Przepływ pracy przyjęty przez NLTK polega na tym, że najpierw tokenizujesz na zdania, a następnie każde zdanie na słowa. Dlatego word_tokenize()nie działa z wieloma zdaniami. Aby pozbyć się interpunkcji, możesz użyć wyrażenia regularnego lub isalnum()funkcji Pythona .
Suzana

2
To czyni pracę: >>> 'with dot.'.translate(None, string.punctuation) 'with dot'(uwaga bez kropki na końcu wyniku) może powodować problemy, jeśli masz takie rzeczy 'end of sentence.No space', w tym przypadku to zrobić w zamian: the_text.translate(string.maketrans(string.punctuation, ' '*len(string.punctuation)))która zastępuje wszystkie znaki interpunkcyjne z białymi spacjami.
Bakuriu

Ups, to rzeczywiście działa, ale nie z ciągami znaków Unicode.
lizarisk

Odpowiedzi:


162

Spójrz na inne opcje tokenizacji, które oferuje nltk tutaj . Na przykład możesz zdefiniować tokenizer, który wybiera sekwencje znaków alfanumerycznych jako tokeny i odrzuca wszystko inne:

from nltk.tokenize import RegexpTokenizer

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

Wynik:

['Eighty', 'seven', 'miles', 'to', 'go', 'yet', 'Onward']

55
Zauważ, że jeśli użyjesz tej opcji, stracisz cechy języka naturalnego, takie word_tokenizejak rozszczepianie skurczów. Możesz naiwnie podzielić wyrażenie regularne \w+bez potrzeby używania NLTK.
sffc

3
Aby zilustrować komentarz @sffc, możesz stracić słowa, takie jak „Pan”
geekazoid

jego zamiana „n't” na „t”, jak się tego pozbyć?
Md. Ashikur Rahman

46

Naprawdę nie potrzebujesz NLTK, aby usunąć znaki interpunkcyjne. Możesz go usunąć za pomocą prostego Pythona. Na smyczki:

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

Lub dla Unicode:

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

a następnie użyj tego ciągu w swoim tokenizerze.

Moduł stringów PS ma kilka innych zestawów elementów, które można usunąć (np. Cyfry).


3
Usuń wszystkie znaki interpunkcyjne, używając wyrażenia listy, które również działa. a = "*fa,fd.1lk#$" print("".join([w for w in a if w not in string.punctuation]))
Johnny Zhang

32

Poniższy kod usunie wszystkie znaki interpunkcyjne, a także znaki spoza alfabetu. Skopiowane z ich książki.

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)

wynik

['i', 'ca', 'do', 'this', 'now', 'because', 'i', 'so', 'tired', 'please', 'give', 'me', 'some', 'time', 'sd']

17
Pamiętaj tylko, że używając tej metody, stracisz słowo „nie” w przypadkach takich jak „nie mogę” lub „nie”, co może być bardzo ważne dla zrozumienia i klasyfikacji zdania. Lepiej jest użyć zdania.translate (string.maketrans ("", "",), chars_to_remove), gdzie chars_to_remove może oznaczać "., ':;!?"
MikeL

3
@MikeL Nie możesz obejść słów takich jak „nie można” i „nie”, importując kontrakty i kontrakcje.fix (zdanie_tutaj) przed tokanizacją. Zamieni się „nie mogę” w „nie można” i „nie” w „nie rób”.
zipline86

16

Jak zauważono w komentarzach, zaczynaj się od sent_tokenize (), ponieważ word_tokenize () działa tylko na jednym zdaniu. Możesz odfiltrować znaki interpunkcyjne za pomocą funkcji filter (). A jeśli masz łańcuchy znaków Unicode, upewnij się, że jest to obiekt Unicode (a nie „str” zakodowany za pomocą jakiegoś kodowania, takiego jak „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)

14
Większość złożoności związanej z tokenizerem Penn Treebank dotyczy właściwej obsługi znaków interpunkcyjnych. Po co używać drogiego tokenizera, który dobrze obsługuje znaki interpunkcyjne, jeśli zamierzasz usunąć tylko znaki interpunkcyjne?
rmalouf

3
word_tokenizeto funkcja, która zwraca [token for sent in sent_tokenize(text, language) for token in _treebank_word_tokenize(sent)]. Więc myślę, że twoja odpowiedź to robienie tego, co już robi nltk: używanie sent_tokenize()przed użyciem word_tokenize(). Przynajmniej dotyczy to nltk3.
Kurt Bourbaki

2
@rmalouf, ponieważ nie potrzebujesz tokenów zawierających tylko znaki interpunkcyjne? Więc chcesz did, a n'tjednak nie.
Ciprian Tomoiagă

11

Właśnie użyłem następującego kodu, który usunął całą interpunkcję:

tokens = nltk.wordpunct_tokenize(raw)

type(tokens)

text = nltk.Text(tokens)

type(text)  

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

2
po co konwertować tokeny na tekst?
Sadik

6

Myślę, że potrzebujesz jakiegoś dopasowania wyrażeń regularnych (poniższy kod jest w Pythonie 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)

Wynik:

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

Powinien działać dobrze w większości przypadków, ponieważ usuwa znaki interpunkcyjne, jednocześnie zachowując tokeny, takie jak „n't”, których nie można uzyskać z tokenizatorów regex, takich jak wordpunct_tokenize.


To również usunie takie rzeczy, jak ...i --zachowując skurcze, co s.translate(None, string.punctuation)nie będzie
CJ Jackson

5

Szczerze pytasz, co to jest słowo? Jeśli zakładasz, że słowo składa się tylko ze znaków alfabetu, to się mylisz, ponieważ słowa takie jak can'tzostaną zniszczone na kawałki (takie jak cani t), jeśli usuniesz znaki interpunkcyjne przed tokenizacją , co z dużym prawdopodobieństwem wpłynie negatywnie na Twój program.

Dlatego rozwiązaniem jest tokenizacja, a następnie usunięcie tokenów interpunkcyjnych .

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

... a jeśli chcesz, możesz zastąpić pewne znaki, takie jak 'mz am.


4

Używam tego kodu, aby usunąć interpunkcję:

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

A jeśli chcesz sprawdzić, czy token jest prawidłowym angielskim słowem, czy nie, możesz potrzebować PyEnchant

Instruktaż:

 import enchant
 d = enchant.Dict("en_US")
 d.check("Hello")
 d.check("Helo")
 d.suggest("Helo")

2
Uważaj, to rozwiązanie zabija skurcze. To dlatego, że word_tokenizestosowanie średnia tokenizer, TreebankWordTokenizer, która dzieli skurcze (np can'tdo ( ca, n't) Jednakże, n'tnie jest alfanumeryczny i zgubić się w tym procesie.
Diego Ferri

1

Usuń interpunkcję (usunie., A także część obsługi interpunkcji za pomocą poniższego kodu)

        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 

Przykładowe wejście / wyjście:

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


Dziękuję bardzo

1

Samo dodanie do rozwiązania przez @rmalouf nie będzie zawierało żadnych liczb, ponieważ \ w + jest równoważne z [a-zA-Z0-9_]

from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer(r'[a-zA-Z]')
tokenizer.tokenize('Eighty-seven miles to go, yet.  Onward!')

Ten tworzy jeden token dla każdej litery.
Rishabh Gupta

1

Możesz to zrobić w jednej linii bez nltk (python 3.x).

import string
string_text= string_text.translate(str.maketrans('','',string.punctuation))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.