Nltk stemmer: индекс строки вне диапазона

У меня есть набор маринованных текстовых документов, которые я хотел бы использовать с помощью nltk PorterStemmer. По причинам, специфичным для моего проекта, я хотел бы сделать вывод из представления приложения django.

Однако, когда вы создаете документы внутри представления django, я получаю исключение IndexError: string index out of range из PorterStemmer().stem() для строки 'oed'. В результате выполните следующие действия:

# xkcd_project/search/views.py
from nltk.stem.porter import PorterStemmer

def get_results(request):
    s = PorterStemmer()
    s.stem('oed')
    return render(request, 'list.html')

вызывает указанную ошибку:

Traceback (most recent call last):
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/jkarimi91/Projects/xkcd_search/xkcd_project/search/views.py", line 15, in get_results
    s.stem('oed')
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/nltk/stem/porter.py", line 665, in stem
    stem = self._step1b(stem)
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/nltk/stem/porter.py", line 376, in _step1b
    lambda stem: (self._measure(stem) == 1 and
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/nltk/stem/porter.py", line 258, in _apply_rule_list
    if suffix == '*d' and self._ends_double_consonant(word):
  File "//anaconda/envs/xkcd/lib/python2.7/site-packages/nltk/stem/porter.py", line 214, in _ends_double_consonant
    word[-1] == word[-2] and
IndexError: string index out of range

Теперь, что действительно странно, работает тот же самый стэммер в той же строке вне django (будь то отдельный файл python или интерактивная консоль python) не вызывает ошибок. Другими словами:

# test.py
from nltk.stem.porter import PorterStemmer
s = PorterStemmer()
print s.stem('oed')

а затем:

python test.py
# successfully prints 'o'

что вызывает эту проблему?

Ответы

Ответ 1

Это ошибка NLTK, относящаяся к NLTK версии 3.2.2, для которой я виноват. Он был введен PR https://github.com/nltk/nltk/pull/1261, который переписал ствол Портера.

Я написал исправление, которое вышло в NLTK 3.2.3. Если вы находитесь на версии 3.2.2 и хотите исправить, просто обновите - например. запустив

pip install -U nltk

Ответ 2

Я отлаживал модуль nltk.stem.porter, используя pdb. После нескольких итераций в _apply_rule_list() вы получите:

>>> rule
(u'at', u'ate', None)
>>> word
u'o'

В этот момент метод _ends_double_consonant() пытается выполнить word[-1] == word[-2], и он терпит неудачу.

Если я не ошибаюсь, в NLTK 3.2 относительный метод

Насколько я вижу, в новой версии отсутствует проверка len(word) < 2.

Изменение _ends_double_consonant() на что-то вроде этого должно работать:

def _ends_double_consonant(self, word):
      """Implements condition *d from the paper

      Returns True if word ends with a double consonant
      """
      if len(word) < 2:
          return False
      return (
          word[-1] == word[-2] and
          self._is_consonant(word, len(word)-1)
      )

Я только что предложил это изменение в связанной с этим проблеме NLTK.