Как избавиться от знаков препинания с помощью токенизатора NLTK?

125

Я только начинаю использовать NLTK и не совсем понимаю, как получить список слов из текста. Если я использую nltk.word_tokenize(), я получаю список слов и знаков препинания. Вместо этого мне нужны только слова. Как избавиться от знаков препинания? Также word_tokenizeне работает с несколькими предложениями: к последнему слову добавляются точки.

lizarisk
источник
12
Почему бы вам самому не убрать знаки препинания? nltk.word_tokenize(the_text.translate(None, string.punctuation))должен работать в python2, а в python3 вы можете nltk.work_tokenize(the_text.translate(dict.fromkeys(string.punctuation))).
Bakuriu
3
Это не работает. С текстом ничего не происходит.
lizarisk
Рабочий процесс, предполагаемый NLTK, заключается в том, что вы сначала токенизируете предложения, а затем каждое предложение - словами. Вот почему word_tokenize()не работает с несколькими предложениями. Чтобы избавиться от знаков препинания, вы можете использовать регулярное выражение или isalnum()функцию Python .
Suzana
2
Он действительно работает: >>> 'with dot.'.translate(None, string.punctuation) 'with dot'(обратите внимание на отсутствие точки в конце результата). Это может вызвать проблемы, если у вас есть такие вещи, как 'end of sentence.No space', в этом случае, сделайте это вместо: the_text.translate(string.maketrans(string.punctuation, ' '*len(string.punctuation)))который заменяет все знаки препинания пробелами.
Bakuriu
К сожалению, это действительно работает, но не со строками 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']
rmalouf
источник
55
Обратите внимание, что если вы используете эту опцию, вы теряете функции естественного языка, такие word_tokenizeкак разделение сокращений. Вы можете наивно разделить на регулярное выражение \w+без необходимости в NLTK.
sffc 08
3
Чтобы проиллюстрировать комментарий @sffc, вы можете потерять такие слова, как "Mr."
geekazoid
его замена «n't» на «t», как от этого избавиться?
Md. Ashikur Rahman
46

Для удаления знаков препинания вам действительно не нужен NLTK. Вы можете удалить его простым питоном. Для струнных:

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

Или для юникода:

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 Вы не можете обойти такие слова, как «не могу» и «не делать», импортируя сокращение и сокращение.fix (предложение_здесь) перед токанизацией. Он превратит «не могу» в «не могу», а «не могу» - в «не надо».
zipline86
16

Как отмечалось в комментариях, начинаются с sent_tokenize (), потому что word_tokenize () работает только с одним предложением. Вы можете отфильтровать знаки препинания с помощью filter (). И если у вас есть строки 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)
palooh
источник
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")
zhenv5
источник
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']

ascii_walker
источник
Большое спасибо
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))
Нишан Викрамаратна
источник