Как мне сделать слово «Стемминг» или «Лемматизация»? - PullRequest
106 голосов
/ 21 апреля 2009

Я пробовал PorterStemmer и Snowball, но оба не работают на всех словах, пропуская некоторые очень распространенные.

Мои тестовые слова: « кошки, бегущие по кактусам, кактусам, сообществам кактусов », и оба получают право наполовину меньше.

Смотри также:

Ответы [ 21 ]

140 голосов
/ 04 мая 2009

Если вы знаете Python, Natural Language Toolkit (NLTK) имеет очень мощный лемматизатор, который использует WordNet .

Обратите внимание, что если вы используете этот лемматизатор в первый раз, вы должны загрузить корпус до его использования. Это может быть сделано:

>>> import nltk
>>> nltk.download('wordnet')

Вы должны сделать это только один раз. Предполагая, что вы уже загрузили корпус, он работает так:

>>> from nltk.stem.wordnet import WordNetLemmatizer
>>> lmtzr = WordNetLemmatizer()
>>> lmtzr.lemmatize('cars')
'car'
>>> lmtzr.lemmatize('feet')
'foot'
>>> lmtzr.lemmatize('people')
'people'
>>> lmtzr.lemmatize('fantasized','v')
'fantasize'

В модуле nltk.stem есть и другие лемматизаторы, но я сам их не пробовал.

29 голосов
/ 02 марта 2012

Я использую Стэнфордский НЛП для выполнения лемматизации. Я застрял с подобной проблемой в последние несколько дней. Все благодаря stackoverflow, чтобы помочь мне решить эту проблему.

import java.util.*; 
import edu.stanford.nlp.pipeline.*;
import edu.stanford.nlp.ling.*; 
import edu.stanford.nlp.ling.CoreAnnotations.*;  

public class example
{
    public static void main(String[] args)
    {
        Properties props = new Properties(); 
        props.put("annotators", "tokenize, ssplit, pos, lemma"); 
        pipeline = new StanfordCoreNLP(props, false);
        String text = /* the string you want */; 
        Annotation document = pipeline.process(text);  

        for(CoreMap sentence: document.get(SentencesAnnotation.class))
        {    
            for(CoreLabel token: sentence.get(TokensAnnotation.class))
            {       
                String word = token.get(TextAnnotation.class);      
                String lemma = token.get(LemmaAnnotation.class); 
                System.out.println("lemmatized version :" + lemma);
            }
        }
    }
}

Также было бы неплохо использовать стоп-слова для минимизации выходных лемм, если они будут использованы позже в классификаторе. Пожалуйста, обратите внимание на расширение coreNlp , написанное Джоном Конвеллом.

24 голосов
/ 21 апреля 2009

Я попробовал ваш список терминов на этом демонстрационном сайте снежного кома , и результаты выглядят хорошо ....

  • кошки -> кошка
  • работает -> запустить
  • побежал -> побежал
  • Кактус -> Кактус
  • кактусы -> кактусы
  • сообщество -> сообщество
  • сообщества -> коммунити

Предполагается, что парашютист превращает словесные формы слов в какой-то общий корень. На самом деле задача не состоит в том, чтобы превратить этот корень в «правильное» словарное слово. Для этого вам нужно взглянуть на морфологические / орфографические анализаторы .

Я думаю, этот вопрос - это примерно то же самое, и ответ Каарела на этот вопрос - откуда я взял вторую ссылку.

20 голосов
/ 09 марта 2014

Продолжаются дебаты о том, что происходит против лемматизатора. Это вопрос предпочтения точности, а не эффективности. Вы должны лемматизировать, чтобы получить лингвистически значимые единицы и использовать минимальный вычислительный сок, и при этом индексировать слово и его варианты под одним ключом.

См. Stemmers vs Lemmatizers

Вот пример с python NLTK:

>>> sent = "cats running ran cactus cactuses cacti community communities"
>>> from nltk.stem import PorterStemmer, WordNetLemmatizer
>>>
>>> port = PorterStemmer()
>>> " ".join([port.stem(i) for i in sent.split()])
'cat run ran cactu cactus cacti commun commun'
>>>
>>> wnl = WordNetLemmatizer()
>>> " ".join([wnl.lemmatize(i) for i in sent.split()])
'cat running ran cactus cactus cactus community community'
8 голосов
/ 21 апреля 2009

Официальная страница Мартина Портера содержит Porter Stemmer на PHP , а также другие языки .

Если вы действительно серьезно относитесь к хорошему основанию, хотя вам нужно начать с чего-то вроде алгоритма Портера, уточните его, добавив правила для исправления неправильных случаев, общих для вашего набора данных, и, наконец, добавьте множество исключений к правилам. Это может быть легко реализовано с помощью пар ключ / значение (dbm / hash / dictionaries), где ключ - это слово, которое нужно искать, а значение - это слово с основанием для замены оригинала. Коммерческая поисковая система, над которой я работал, однажды закончилась 800 исключениями из модифицированного алгоритма Портера.

5 голосов
/ 21 апреля 2009

http://wordnet.princeton.edu/man/morph.3WN

Для большинства моих проектов я предпочитаю лемматизатор WordNet, основанный на лексиконе, а не более агрессивному портеру.

http://wordnet.princeton.edu/links#PHP имеет ссылку на PHP-интерфейс к API-интерфейсам WN.

4 голосов
/ 22 февраля 2018

Основываясь на различных ответах о переполнении стека и блогах, с которыми я сталкивался, я использую этот метод, и, похоже, он вполне возвращает реальные слова. Идея состоит в том, чтобы разбить входящий текст на массив слов (используйте любой метод, который вам нужен), а затем найдите части речи (POS) для этих слов и используйте их, чтобы помочь выделить и лемматизировать слова.

Ваш пример выше не работает, потому что POS не может быть определен. Однако, если мы используем реальное предложение, все работает намного лучше.

import nltk
from nltk.corpus import wordnet

lmtzr = nltk.WordNetLemmatizer().lemmatize


def get_wordnet_pos(treebank_tag):
    if treebank_tag.startswith('J'):
        return wordnet.ADJ
    elif treebank_tag.startswith('V'):
        return wordnet.VERB
    elif treebank_tag.startswith('N'):
        return wordnet.NOUN
    elif treebank_tag.startswith('R'):
        return wordnet.ADV
    else:
        return wordnet.NOUN


def normalize_text(text):
    word_pos = nltk.pos_tag(nltk.word_tokenize(text))
    lemm_words = [lmtzr(sw[0], get_wordnet_pos(sw[1])) for sw in word_pos]

    return [x.lower() for x in lemm_words]

print(normalize_text('cats running ran cactus cactuses cacti community communities'))
# ['cat', 'run', 'ran', 'cactus', 'cactuses', 'cacti', 'community', 'community']

print(normalize_text('The cactus ran to the community to see the cats running around cacti between communities.'))
# ['the', 'cactus', 'run', 'to', 'the', 'community', 'to', 'see', 'the', 'cat', 'run', 'around', 'cactus', 'between', 'community', '.']
3 голосов
/ 21 апреля 2009

Загляните в WordNet, большую лексическую базу данных для английского языка:

http://wordnet.princeton.edu/

Существуют API для доступа к нему на нескольких языках.

2 голосов
/ 18 мая 2014

Посмотрите на LemmaGen - библиотека с открытым исходным кодом, написанная на C # 3.0.

Результаты для ваших тестовых слов (http://lemmatise.ijs.si/Services)

  • кошки -> кошка
  • работает
  • бежал -> бегал
  • кактус
  • кактусы -> кактусы
  • Кактусы -> Кактус
  • сообщество
  • сообщества -> сообщество
2 голосов
/ 29 октября 2012

Это выглядит интересно: MIT Java WordnetStemmer: http://projects.csail.mit.edu/jwi/api/edu/mit/jwi/morph/WordnetStemmer.html

...