Як позбутися пунктуації за допомогою токенізатора 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.