Як позбутися пунктуації за допомогою токенізатора NLTK?


125

Я тільки починаю використовувати NLTK і не зовсім розумію, як отримати список слів з тексту. Якщо я використовую nltk.word_tokenize(), я отримую список слів і розділові знаки. Мені потрібні лише слова. Як я можу позбутися пунктуації? Також word_tokenizeне працює з кількома реченнями: крапки додаються до останнього слова.


12
Чому ви не знімете розділові знаки самостійно? nltk.word_tokenize(the_text.translate(None, string.punctuation))повинен працювати в python2, тоді як у python3 ви можете це зробити nltk.work_tokenize(the_text.translate(dict.fromkeys(string.punctuation))).
Бакуріу

3
Це не працює. З текстом нічого не відбувається.
lizarisk

Робочий процес, який передбачає НЛТК, полягає в тому, що ви спочатку позначаєте слова реченнями, а потім кожне речення словами. Ось чому word_tokenize()не працює з кількома реченнями. Щоб позбутися пунктуації, ви можете використовувати регулярний вираз або isalnum()функцію пітона .
Сузана

2
Це робить роботу: >>> 'with dot.'.translate(None, string.punctuation) 'with dot'(примітка не точка в кінці результату) Це може викликати проблеми , якщо у вас є такі речі , як 'end of sentence.No space', в цьому випадку зробити це замість: the_text.translate(string.maketrans(string.punctuation, ' '*len(string.punctuation)))який замінює всі знаки пунктуації з пробілами.
Бакуріу

На жаль, це дійсно працює, але не з рядками Unicode.
lizarisk

Відповіді:


162

Погляньте на інші варіанти токенізації, які тут надає nltk . Наприклад, ви можете визначити токенізатор, який вибирає послідовності буквено-цифрових символів як лексем і скидає все інше:

from nltk.tokenize import RegexpTokenizer

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

Вихід:

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

55
Зауважте, що якщо ви користуєтеся цією опцією, ви втрачаєте особливості природної мови, такі, word_tokenizeяк поділ скорочень. Ви можете наївно розділити на регулярний вираз \w+без будь-якої необхідності для NLTK.
sffc

3
Щоб проілюструвати коментар @sffc, ви можете втратити слова типу "Mr."
geekazoid

її заміна 'n't' на 't' як позбутися цього?
Пані Ашикур Рахман

46

Вам не дуже потрібно NLTK для видалення пунктуації. Видалити його можна за допомогою простого пітона. Для рядків:

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

Або для unicode:

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

а потім використовуйте цей рядок у своєму токенізаторі.

Модуль рядка PS має деякі інші набори елементів, які можна видалити (наприклад, цифри).


3
Видаліть усі розділові знаки, використовуючи список вираз, який також працює. a = "*fa,fd.1lk#$" print("".join([w for w in a if w not in string.punctuation]))
Джонні Чжан

32

Знизу код видалить усі розділові знаки, а також не алфавітні символи. Скопійовано з їхньої книги.

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)

вихід

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

17
Просто майте на увазі, що, використовуючи цей метод, ви втратите слово "не" у випадках, як "не можу" або "не", що може бути дуже важливим для розуміння та класифікації речення. Краще скористатись пропозицією.translate (string.maketrans ("", "",), chars_to_remove), де chars_to_remove може бути "., ':;!?"
MikeL

3
@MikeL Ви не можете обійти такі слова, як "не можу" та "не", імпортуючи скорочення та contractions.fix (речення_туть) перед токанізацією. Це перетвориться на "не можна" в "не можна" і "не" в "не робити".
zipline86

16

Як зазначається в коментарях, почніть з sent_tokenize (), оскільки word_tokenize () працює лише на одне речення. Ви можете відфільтрувати розділові знаки за допомогою фільтра (). І якщо у вас є рядки Unicode, переконайтеся, що це об’єкт unicode (а не "str", кодований деяким кодуванням, наприклад "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
Більшість складностей, пов'язаних з токенізатором Penn Treebank, пов'язане з правильним поводженням з пунктуацією. Навіщо використовувати дорогий токенізатор, який добре поводиться з пунктуацією, якщо ви збираєтесь лише викреслити пунктуацію?
rmalouf

3
word_tokenizeце функція, яка повертається [token for sent in sent_tokenize(text, language) for token in _treebank_word_tokenize(sent)]. Тому я думаю, що ваша відповідь робить те, що nltk вже робить: використання sent_tokenize()перед використанням word_tokenize(). Принаймні, це для nltk3.
Курт Бурбакі

2
@rmalouf, тому що вам не потрібні знаки, що містять розділові знаки? Так що ви хочете didі , n'tале не.
Кипріян Tomoiagă

11

Я просто використав наступний код, який видалив усі розділові знаки:

tokens = nltk.wordpunct_tokenize(raw)

type(tokens)

text = nltk.Text(tokens)

type(text)  

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

2
навіщо перетворювати лексеми в текст?
Садик

6

Я думаю, вам потрібна якась регулярна відповідність виразів (наступний код знаходиться в 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)

Вихід:

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

Потрібно добре працювати в більшості випадків, оскільки він видаляє пунктуацію, зберігаючи лексеми типу "n't", які неможливо отримати від регекс-токенізаторів, таких як wordpunct_tokenize.


Це також видалить такі речі, як ...і збереже --сутички, яких s.translate(None, string.punctuation)не буде
CJ Jackson

5

Щиро запитуючи, що таке слово? Якщо ви припускаєте, що слово складається лише з алфавітних символів, ви помиляєтесь, оскільки такі слова, як, наприклад, can'tбудуть знищені на частини (наприклад, canта t), якщо ви видалите пунктуацію перед маркірацією , що, швидше за все, негативно вплине на вашу програму.

Отже, рішення полягає в токенізації, а потім видаленні знаків пунктуації .

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

... а потім, якщо хочете, ви можете замінити певні жетони, наприклад, 'mна am.


4

Я використовую цей код для видалення пунктуації:

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

І якщо ви хочете перевірити, чи маркер є правильним англійським словом чи ні, вам може знадобитися PyEnchant

Підручник:

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

2
Слідкуйте за тим, що це рішення вбиває сутички. Це тому, що word_tokenizeвикористовуйте стандартний токенізатор, TreebankWordTokenizerякий розбиває скорочення (наприклад, can'tдо ( ca, n't). Однак n'tце не буквено-цифровий і втрачається в процесі.
Дієго Феррі

1

Видалити пунктуацію (вилучить. А також частину обробки пунктуації за допомогою наведеного нижче коду)

        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 

Зразок вводу / виводу:

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


Дуже дякую

1

Лише додавши до рішення @rmalouf, це не включатиме жодних чисел, оскільки \ w + еквівалентно [a-zA-Z0-9_]

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

Цей створює один маркер для кожної літери.
Рішабх Гупта

1

Ви можете зробити це в одному рядку без nltk (python 3.x).

import string
string_text= string_text.translate(str.maketrans('','',string.punctuation))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.