2017-01-07 56 views
14

Mam zestaw piklowanych dokumentów tekstowych, które chciałabym wykorzystać przy użyciu nltk's PorterStemmer. Ze względów specyficznych dla mojego projektu chciałbym zrobić wynik wewnątrz widoku aplikacji django.trzpień nltk: indeks ciągów poza zakresem

Jednak po podziale dokumentów wewnątrz widoku django otrzymuję wyjątek IndexError: string index out of range od PorterStemmer().stem() dla ciągu znaków 'oed'. W rezultacie, uruchamiając następujące:

# 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') 

podnosi wymieniony błąd:

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 

co teraz jest naprawdę dziwne jest uruchomiony ten sam Stemmer na tym samym ciąg zewnątrz Django (może to być oddzielna plik python lub interaktywna konsola pythona) nie powoduje błędów. Innymi słowy:

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

następuje:

python test.py 
# successfully prints 'o' 

, co jest przyczyną tego problemu?

+0

Czy używasz Pythona 2? To może być różnica w zestawie znaków - tylko zgadywanie. – alexis

+2

Jakiej wersji NLTK używasz? Możesz to sprawdzić za pomocą 'nltk .__ version__' po zaimportowaniu. Być może używasz dwóch różnych wersji dla django i zewnętrznego pythona. Czy mógłbyś również sprawdzić wersję pythona, której używasz w django i uruchomić zewnętrzny skrypt? Przypuszczam, że zawsze jest '2.7', biorąc pod uwagę instrukcję' print'. –

+1

Prawie niezwiązane z problemem, 's = PorterStemmer()' należy umieścić gdzieś w zmiennych globalnych. Umieszczenie ich w widoku oznacza załadowanie obiektu 'PorterStemmer' dla każdej strony, która ładuje tę funkcję widoku. – alvas

Odpowiedz

28

To jest błąd NLTK specyficzny dla NLTK w wersji 3.2.2, za który jestem odpowiedzialny. Został on wprowadzony przez PR https://github.com/nltk/nltk/pull/1261, który przepisał łobuzer Portera.

Napisałem a fix, który wyszedł w NLTK 3.2.3. Jeśli używasz wersji 3.2.2 i chcesz naprawić, po prostu zaktualizuj - np. uruchamiając

+5

W obecnej wersji, ta odpowiedź wynosi +20, więc skutecznie otrzymałem 200 powtórzeń przepełnienia stosu jako nagrodę za złamanie biblioteki open source. Czuję się dość winny. –

+0

Nie bądź winny, jest to jeden ze sposobów na zachęcenie OSS =) – alvas

3

I debugowałem moduł nltk.stem.porter przy użyciu pdb. Po kilku iteracjach, w _apply_rule_list() otrzymasz:

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

w tym momencie metoda _ends_double_consonant() próbuje zrobić word[-1] == word[-2] i to się nie powiedzie.

Jeśli się nie mylę, w NLTK 3.2relative method był następujący:

def _doublec(self, word): 
    """doublec(word) is TRUE <=> word ends with a double consonant""" 
    if len(word) < 2: 
     return False 
    if (word[-1] != word[-2]):  
     return False   
    return self._cons(word, len(word)-1) 

O ile widzę, kontrola len(word) < 2 brakuje w nowej wersji.

Zmiana _ends_double_consonant() coś jak to powinno działać:

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

Właśnie zaproponowano tę zmianę związaną NLTK kwestii.

+1

To działało dobrze dla mnie! –