Nltk: A saída do stemmer de Porter é inconsistente com a das implementações de referência

Criado em 17 jan. 2012  ·  8Comentários  ·  Fonte: nltk/nltk

Recentemente, usei o lematizador Porter do NLTK e descobri algumas discrepâncias entre sua saída e a de outra versão do lematizador Porter que usei. Acompanhando essas discrepâncias, descobri que pode haver alguns problemas com a implementação do NLTK.

Existem várias implementações de referência do lematizador Porter coletadas pelo próprio Martin Porter aqui:

http://tartarus.org/~martin/PorterStemmer/

Eu tentei um para o Ruby verificar a sanidade do NLTK (ele pega uma palavra do padrão e expõe sua forma radical imediatamente, também no padrão):

scripts $ ruby ​​porter_stemmer.rb
brilhante
Shini

Eu verifiquei isso contra o NLTK:

scripts $ python
Python 2.6.1 (r261: 67515, 24 de junho de 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] em darwin
Digite "ajuda", "direitos autorais", "créditos" ou "licença" para obter mais informações.

        import nltk
        nltk.stem.porter.PorterStemmer().stem_word('shiny')

'shini'

Até agora tudo bem. E se eu comparar esses resultados com os resultados esperados (output.txt) fornecidos na mesma página para um exemplo de arquivo dict do usuário (voc.txt), eles parecem certos:

scripts $ egrep -n '^ brilhante $' voc.txt
18333: brilhante
scripts $ egrep -n '^ shini $' output.txt
18333: shini

Mas se eu comparar sistematicamente os resultados de NLTK com aqueles no arquivo de resultados esperados, vejo muitas discrepâncias (formato: palavra, lematização esperada adequada, lematização de NLTK incorreta marcada por asterisco):

scripts $ ./show_bad_stemming_in_nltk.py voc.txt output.txt
abadia abadia * abadia
abadias abadia * abadia
abed ab * abe
absey absei * absey
[...]
irônico irônico * wri
ontem yesterdai * ontem
ontem yesterdai * ontem
yongrey yongrei * yongrey

A verificação pontual contra a implementação de referência Ruby confirma que os resultados de NLTK são de fato o problema:

scripts $ ruby ​​porter_stemmer.rb
Mosteiro
abbei
abadias
abbei
cama
ab
absey
absei
irônico
irônico
ontem
yesterdai
de ontem
yesterdai
Yongrey
Yongrei

Anexei a lista completa de palavras para as quais o lematizador Porter da NLTK fornece resultados inesperados.

(Este bug pertence à versão 2.0b9. Suspeito que existe em todas as versões anteriores, mas não o confirmei.)

Migrado de http://code.google.com/p/nltk/issues/detail?id=625


comentários anteriores

gregg.lind disse, em 2011-02-09T20: 22: 57.000Z:

Eu ficaria feliz em fazer este (até sexta-feira), se ninguém mais quiser. Tenho usado muito este módulo. Gregg Lind

StevenBird1 disse, em 2011-02-14T07: 14: 49.000Z:

Em anexo estão as correções de Stuart Robinson, enviadas para nltk-dev. Isso parece ser mais edições da versão anterior, ao invés de um novo porte da versão Ruby como discutido originalmente. Antes que esta nova versão possa ser incorporada, precisamos de um conjunto de casos de teste adicionados a test / stem.doctest.

goodfirstbug

Comentários muito úteis

@paulproteus - finalmente resolvido

Todos 8 comentários

Acabei de colocar o rótulo "goodfirstbug" neste aqui. O "bom primeiro bug" seria adicionar um monte de casos de teste a stem.doctest (https://github.com/nltk/nltk/blob/master/nltk/test/stem.doctest) - se você quiser mesclar nas correções de Stuart também, isso seria ótimo!

Olá a todos, especialmente @alexrudnick , isso deve ser marcado como resolvido agora?

Após uma leitura rápida, parece que não, ainda não foi resolvido. Mas gostaria de ouvir de um mantenedor.

@paulproteus - finalmente resolvido

Observe que o comportamento do lematizador _padrão_ no meu PR que Steven acabou de mesclar permanece inalterado; você precisa passar explicitamente mode=PorterStemmer.MARTIN_EXTENSIONS para o construtor PorterStemmer para obter um comportamento consistente com as implementações de referência de Martin (que são inconsistentes com o algoritmo original de Martin).

Indiscutivelmente, ter MARTIN_EXTENSIONS como o modo padrão (para consistência com as implementações de referência) seria melhor, já que os usuários vão esperar algo chamado PorterStemmer para se comportar fora da caixa como as implementações de referência de Martin. O problema é que isso seria uma quebra de compatibilidade com versões anteriores, e desagradavelmente não óbvia; alguém usando a implementação anterior do NLTK que atualiza o NLTK pode deixar de notar por um longo tempo que apenas algumas de suas raízes mudaram, possivelmente introduzindo bugs sutis dependendo do seu caso de uso. Outra opção é não ter um valor padrão e exigir que cada usuário leia a documentação sobre os diferentes modos e escolha explicitamente qual usar. Isso quebraria a compatibilidade com versões anteriores também, mas faria isso de uma maneira _obvious_ (apenas tentar instanciar o lematizador da maneira antiga explodiria) para que as pessoas fazendo atualizações sem ler as notas de lançamento não fossem pegas. Essa abordagem evitaria qualquer um dos cenários ruins acima, mas ao custo de exigir mais trabalho inicial de cada novo usuário do lematizador.

Nenhuma das opções é perfeita. Optei por ter NLTK_EXTENSIONS como padrão, mas há espaço para discordar. Alguém tem uma opinião?

@ExplodingCabbage : Eu

Oi, pessoal,

Eu tenho escrito um back-end de mecanismo de pesquisa com o PorterStemmer padrão em nltk, sem saber que ele não se comporta da mesma maneira que muitas outras implementações de stemmer Porter. Agora que estou trabalhando no front-end usando Javascript, estou encontrando bugs em que o front-end e o meu back-end originam palavras de maneira diferente. Eu queria saber o que devo observar se precisar recriar o comportamento padrão do PorterStemmer do nltk em Javascript para que eu possa executá-lo no navegador. Eu esperava que alguém onde (talvez @ExplodingCabbage ?) Pudesse me apontar a direção certa.

Eu realmente não tenho tempo para reindexar tudo com o modo MARTIN_EXTENSIONS, pois levaria semanas para fazer isso ...

@josephcc porter.py basicamente não tem dependências e não faz nada de profundo ou mágico, apenas uma longa série de manipulações de strings. Você só vai querer portar a classe PorterStemmer para JavaScript, preservando apenas os ramos if self.mode == self.NLTK_EXTENSIONS e jogando fora a lógica dos outros.

Não é uma tarefa de 5 minutos ou infalível, é certo, mas factível. Verifique também PorterTest em https://github.com/nltk/nltk/blob/develop/nltk/test/unit/test_stem.py e considere executar os casos de teste em sua implementação de JavaScript para verificar a exatidão do seu trabalho.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

vezeli picture vezeli  ·  3Comentários

mwess picture mwess  ·  5Comentários

zdog234 picture zdog234  ·  3Comentários

ndvbd picture ndvbd  ·  4Comentários

DavidNemeskey picture DavidNemeskey  ·  4Comentários