2009-04-21 7 views
93

Я пробовал PorterStemmer и Snowball, но оба они не работают над всеми словами, пропуская некоторые очень распространенные.Как я могу сделать слово «Stemming» или «Lemmatization»?

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

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

+22

Не должно быть кактусов? – MSalters

+3

Просто, чтобы сделать круговую ссылку на исходный вопрос, размещенный на Reddit: [Как программно сделать вывод? (например, «есть», «есть», «кактусы» - «кактус»)] (http://www.reddit.com/r/programming/comments/8e5d3/how_do_i_programatically_do_stemming_eg_eating_to/) Публикуется здесь, потому что комментарии включают Полезная информация. –

+1

см. Http://stackoverflow.com/questions/17317418/stemmers-vs-lemmatizers – alvas

ответ

1

сделайте поиск Lucene, я не уверен, если Theres PHP-порт, но я знаю, Lucene доступен для многих платформ , Lucene - это библиотека индексирования и поиска OSS (из Apache). Естественно, что у него и у сообщества есть что-то интересное. По крайней мере, вы можете узнать, как сделать его на одном языке, так что вы можете перевести «идею» в PHP

24

Я попробовал ваш список терминов на this snowball demo site и результаты выглядят нормально ....

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

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

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

+0

Не было впечатлено после первого испытания 'updates -> updat' – Medorator

+3

Дело в том, что стебель (« обновления ») == stem (" обновление »), которое он делает (обновить -> обновить) – Stompchicken

+0

Программное обеспечение может выполнять стебель (x) == stem (y), но это не полностью отвечает на вопрос – Medorator

8

Официальная страница Мартина Портера содержит Porter Stemmer in PHP, а также other languages.

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

+0

Идеальное решение автоматически узнает эти ожидания. Был ли у вас опыт работы с такой системой? – Malcolm

+0

№ В нашем случае проиндексированные документы были кодом и правилами для определенной области права, и были десятки (человеческих) редакторов, анализирующих индексы для любых плохих стеблей. –

1

Если я процитирую свой ответ на этот вопрос StompChicken упоминается:

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

Поскольку они не понимают язык и не работают из словаря терминов, они не могут распознавать и отвечать соответствующим образом на нерегулярные случаи, такие как «бегать»/«бегать».

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

3

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

http://wordnet.princeton.edu/

Есть интерфейсы API для доступа к нему на нескольких языках.

123

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

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

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

Есть другие lemmatizers в nltk.stem module, но я не пробовал их сам.

+7

О, грустно ... прежде, чем я знал, чтобы искать С.О. Я реализовал свои собственные! – Crisfole

+10

Не забудьте установить корпус перед использованием ** nltk ** в первый раз! http://www.velvetcache.org/2010/03/01/looking-up-words-in-a-dictionary-using-python –

+1

Ну, это использует какой-то недетерминированный алгоритм, такой как Porter Stemmer, потому что если вы попробуете он с 'dies', он дает вам' dy' вместо 'die'. Разве нет какого-то жестко закодированного словаря? – SexyBeast

0

.Net lucene имеет встроенный стример портера. Вы можете попробовать это. Но обратите внимание, что при построении леммы портер не учитывает контекст слова. (Пройдите алгоритм и его реализацию, и вы увидите, как он работает)

28

Я использую stanford nlp для выполнения лемматизации. За последние несколько дней я столкнулся с подобной проблемой. Все спасибо 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, написанное Джоном Конуэлом.

+0

извините за поздний ответ .. Я решил эту проблему решить только сейчас! :) – CTsiddharth

+1

Строка 'pipe = new ...' не компилируется для меня. Если я изменю его на «StanfordCoreNLP pipelne = new ...», он компилируется. О, это правильно? –

+0

Да, сначала необходимо сначала объявить конвейер var. Стэнфордская НЛП также может использоваться из командной строки, поэтому вам не нужно программировать, вы просто делаете файл свойств и загружаете с ним исполняемые файлы. Прочтите документы: http://nlp.stanford.edu/software/corenlp.shtml –

1

Вы можете использовать стеммер Морфа. UW имеет uploaded morpha stemmer to Maven central, если вы планируете использовать его из приложения Java. Есть оболочка, которая делает ее намного проще в использовании. Вам просто нужно добавить его как зависимость и использовать класс edu.washington.cs.knowitall.morpha.MorphaStemmer. Экземпляры являются потокобезопасными (исходный JFlex без полей классов для локальных переменных). Создайте экземпляр класса и запустите morpha и слово, которое вы хотите создать.

new MorphaStemmer().morpha("climbed") // goes to "climb" 
2

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

+3

Добро пожаловать в SO, и спасибо за сообщение, +1. Было бы здорово, если бы вы могли сделать несколько замечаний по поводу использования этого сценария, производительности и т. Д. Просто ссылка обычно не считается очень хорошим ответом. – jogojapan

0

Мартин Портер написал Снежка (язык для вытекающих алгоритмов) и переписали "английский парадигматический" в Snowball. Есть английский стриммер для C и Java.

Он прямо заявляет, что Портер Штеммер был переписан только по историческим причинам, так что тестирование правильности вытекающих против Портера Stemmer получите вам результаты, которые вы (должны) уже знаете.

От http://tartarus.org/~martin/PorterStemmer/index.html (курсив)

Портер парадигматический следует рассматривать как «замороженного», то есть, строго определенной, и не поддаются дальнейшей модификации. Как стволовый, он немного уступает стебельке Snowball English или Porter2, который вытекает из него, и который подвергается случайным улучшениям. Поэтому для практической работы рекомендуется использовать новый сноуборд. Покровитель Портера подходит для исследований IR-исследований, связанных с остановкой, когда эксперименты должны быть точно повторяемыми.

Д-р Портер предлагает использовать стволовые средства английского или портера2 вместо стволовых Портер. Английский стволовый - это то, что на самом деле используется в demo site, поскольку @StompChicken ответил ранее.

16

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

См Stemmers vs Lemmatizers

Вот пример с питона 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' 
+1

Как уже упоминалось ранее, 'lemmatize()' WordNetLemmatizer' может принимать тег POS. Итак, из вашего примера: «.» .join ([wnl.lemmatize (i, pos = VERB) для i в send.split()]) 'дает' 'запуск кошки cactus cactus cactus cacti community community''. –

+0

@NickRuiz, я думаю, вы имели в виду 'pos = NOUN'? BTW: Долгое время не вижу, надеюсь, мы скоро встретимся на конференции =) – alvas

+0

на самом деле, нет (надеюсь, «да» на конференциях). Потому что, если вы установите 'pos = VERB', вы делаете лемматизацию только на глаголах. Существительные остаются неизменными. Мне просто пришлось написать свой собственный код, чтобы повернуть вокруг фактических POS-тегов Penn Treebank, чтобы применить правильную лемматизацию к каждому токену. Кроме того, 'WordNetLemmatizer' воняет при леммировании стандартного токенизатора nltk. Поэтому такие примеры, как 'does n't', не lemmatize для' do not'. –

2

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

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

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

В Java, я использую tartargus-snowball морфологии слов

Maven:

<dependency> 
     <groupId>org.apache.lucene</groupId> 
     <artifactId>lucene-snowball</artifactId> 
     <version>3.0.3</version> 
     <scope>test</scope> 
</dependency> 

Пример кода:

SnowballProgram stemmer = new EnglishStemmer(); 
String[] words = new String[]{ 
    "testing", 
    "skincare", 
    "eyecare", 
    "eye", 
    "worked", 
    "read" 
}; 
for (String word : words) { 
    stemmer.setCurrent(word); 
    stemmer.stem(); 
    //debug 
    logger.info("Origin: " + word + " > " + stemmer.getCurrent());// result: test, skincar, eyecar, eye, work, read 
} 
0

Попробуйте это один здесь: http://www.twinword.com/lemmatizer.php

Я ввел ваш запрос в демо-версию "cats running ran cactus cactuses cacti community communities" и получил ["cat", "running", "run", "cactus", "cactus", "cactus", "community", "community"] с необязательным флагом ALL_TOKENS.

Пример кода

Это API, так что вы можете подключиться к нему из любой среды. Вот как выглядит вызов PHP REST.

// These code snippets use an open-source library. http://unirest.io/php 
$response = Unirest\Request::post([ENDPOINT], 
    array(
    "X-Mashape-Key" => [API KEY], 
    "Content-Type" => "application/x-www-form-urlencoded", 
    "Accept" => "application/json" 
), 
    array(
    "text" => "cats running ran cactus cactuses cacti community communities" 
) 
); 
0

основе различных ответов на переполнение стека и блогах я сталкивался, это метод я использую, и это, кажется, вернуться реальные слова достаточно хорошо. Идея состоит в том, чтобы разбить входящий текст на массив слов (использовать какой бы метод вы ни хотели), а затем найти части речи (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', '.'] 

 Смежные вопросы

  • Нет связанных вопросов^_^