Извлечение слов с помощью nltk из немецкого текста

Я пытаюсь извлечь слова из немецкого документа, когда я использую следующий метод, как описано в учебнике nltk, мне не удается получить слова со специальными символами языка.

ptcr = nltk.corpus.PlaintextCorpusReader(Corpus, '.*');
words = nltk.Text(ptcr.words(DocumentName))

Что мне сделать, чтобы получить список слов в документе?

Пример с nltk.tokenize.WordPunctTokenizer() для немецкой фразы Veränderungen über einen Walzer выглядит так:

In [231]: nltk.tokenize.WordPunctTokenizer().tokenize(u"Veränderungen über einen Walzer")

Out[231]: [u'Ver\xc3', u'\xa4', u'nderungen', u'\xc3\xbcber', u'einen', u'Walzer']

В этом примере «ä» рассматривается как разделитель, хотя «ü» им не является.


person red    schedule 05.02.2012    source источник
comment
что вы получаете вместо списка слов? Знаете ли вы кодировку входных файлов?   -  person ptitpoulpe    schedule 05.02.2012
comment
Я получаю список слов, который разделен неправильно, например, немецкая буква «ä» рассматривается как разделитель. кодировка "utf-8".   -  person red    schedule 05.02.2012
comment
это странно, потому что PlaintextCorpusReader использует WordPunctTokenizer(), который обрабатывает юникод для токенизации текста. Не могли бы вы привести пример ошибки с использованием nltk.tokenize.WordPunctTokenizer().tokenize(uyou ошибочный текст)   -  person ptitpoulpe    schedule 05.02.2012


Ответы (3)


Вызовите PlaintextCorpusReader с параметром encoding='utf-8':

ptcr = nltk.corpus.PlaintextCorpusReader(Corpus, '.*', encoding='utf-8')

Изменить: я вижу... у вас здесь две отдельные проблемы:

а) Проблема токенизации: когда вы тестируете буквальную строку с немецкого языка, вы думаете, что вводите Unicode. На самом деле вы говорите python взять байты между кавычками и преобразовать их в строку Unicode. Но ваши байты неправильно интерпретируются. Исправление: добавьте следующую строку в самый верх исходного файла.

# -*- coding: utf-8 -*-

Внезапно ваши константы будут видны и токенизированы правильно:

german = u"Veränderungen über einen Walzer"
print nltk.tokenize.WordPunctTokenizer().tokenize(german)

Вторая проблема: оказывается, что Text() не использует юникод! Если вы передадите ему строку Unicode, он попытается преобразовать ее в строку чистого ASCII, что, конечно, не работает при вводе не-ASCII. Фу.

Решение: я бы порекомендовал полностью избегать использования nltk.Text и работать непосредственно с читателями корпуса. (В целом это хорошая идея: см. собственную документацию nltk.Text).

Но если вы должны использовать nltk.Text с немецкими данными, вот как это сделать: правильно прочитайте свои данные, чтобы их можно было разбить на токены, а затем «закодируйте» свой Unicode обратно в список str. Для немецкого языка, вероятно, безопаснее просто использовать кодировку Latin-1, но, похоже, utf-8 тоже работает.

ptcr = nltk.corpus.PlaintextCorpusReader(Corpus, '.*', encoding='utf-8');

# Convert unicode to utf8-encoded str
coded = [ tok.encode('utf-8') for tok in ptcr.words(DocumentName) ]
words = nltk.Text(coded)
person alexis    schedule 06.02.2012
comment
это дает мне список слов, когда я инкапсулирую с помощью nltk.Text, я получаю, что кодек ascii не может кодировать символ u'\xdf' в позиции 2: порядковый номер не в диапазоне (128). Я думаю, что это проблема кодирования декодирования. - person red; 09.02.2012
comment
У вас точно проблема с кодировкой, а точнее две. Смотрите обновленный ответ. - person alexis; 29.02.2012

Взгляните на http://text-processing.com/demo/tokenize/. Я не уверен, что ваш текст получает правильную кодировку, так как WordPunctTokenizer в демо-версии прекрасно обрабатывает слова. Как и PunktWordTokenizer.

person Jacob    schedule 06.02.2012
comment
Я проверил это, но я думаю, что они решают проблему неявно: D. - person red; 09.02.2012

Вы можете попробовать простое регулярное выражение. Следующего достаточно, если вам нужны только слова; он проглотит все знаки препинания:

>>> import re
>>> re.findall("\w+", "Veränderungen über einen Walzer.".decode("utf-8"), re.U)
[u'Ver\xe4nderungen', u'\xfcber', u'einen', u'Walzer']

Обратите внимание, что re.U изменяет значение \w в RE в зависимости от текущей локали, поэтому убедитесь, что она установлена ​​правильно. Я установил его на en_US.UTF-8, что, по-видимому, достаточно хорошо для вашего примера.

Также обратите внимание, что "Veränderungen über einen Walzer".decode("utf-8") и u"Veränderungen über einen Walzer" — это разные строки.

person Fred Foo    schedule 06.02.2012