Eu tentei PorterStemmer e Snowball, mas ambos não funcionam em todas as palavras, perdendo algumas muito comuns.
Minhas palavras de teste são: " gatos administrando comunidades de cactos cactos cactos ", e ambas acertam menos da metade.
Veja também:
Eu tentei PorterStemmer e Snowball, mas ambos não funcionam em todas as palavras, perdendo algumas muito comuns.
Minhas palavras de teste são: " gatos administrando comunidades de cactos cactos cactos ", e ambas acertam menos da metade.
Veja também:
Respostas:
Se você conhece Python, o The Natural Language Toolkit (NLTK) tem um lematizador muito poderoso que usa WordNet .
Observe que se você estiver usando este lematizador pela primeira vez, você deve baixar o corpus antes de usá-lo. Isso pode ser feito por:
>>> import nltk
>>> nltk.download('wordnet')
Você só tem que fazer isso uma vez. Supondo que você já tenha baixado o corpus, funciona assim:
>>> 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'
Existem outros lematizadores no módulo nltk.stem , mas não os tentei sozinho.
dies, ele lhe dará ao dyinvés de die. Não existe algum tipo de dicionário de lematizador codificado?
WordNetLemmatizererroneamente lematizam?
Eu uso Stanford nlp para fazer lematização. Tenho enfrentado um problema semelhante nos últimos dias. Tudo graças ao stackoverflow para me ajudar a resolver o problema.
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);
}
}
}
}
Também pode ser uma boa ideia usar palavras irrelevantes para minimizar lemas de saída se forem usadas posteriormente no classificador. Por favor, dê uma olhada na extensão coreNlp escrita por John Conwell.
Tentei sua lista de termos neste site de demonstração de bola de neve e os resultados parecem bons ...
Um lematizador deve transformar as formas flexionadas das palavras em alguma raiz comum. Não é realmente o trabalho de um lematizador fazer dessa raiz uma palavra de dicionário "adequada". Para isso, você precisa olhar para analisadores morfológicos / ortográficos .
Acho que essa pergunta é mais ou menos a mesma coisa, e a resposta de Kaarel a essa pergunta é de onde peguei o segundo link.
Os debates lematizador vs lematizador continuam. É uma questão de preferir a precisão à eficiência. Você deve lematizar para obter unidades e radical lingüisticamente significativas para usar o mínimo de energia de computação e ainda indexar uma palavra e suas variações sob a mesma chave.
Aqui está um exemplo com 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'
WordNetLemmatizer's lemmatize()pode ter um tag POS. Então, do seu exemplo: " ".join([wnl.lemmatize(i, pos=VERB) for i in sent.split()])dá 'cat run run cactus cactuses cacti community communities'.
pos=NOUN? BTW: Há quanto tempo, espero que nos encontremos na conferência em breve =)
pos=VERBvocê só faz a lematização dos verbos. Os substantivos permanecem os mesmos. Eu só tive que escrever um pouco do meu próprio código para girar em torno das tags POS Penn Treebank reais para aplicar a lematização correta a cada token. Além disso, WordNetLemmatizerfede em lematizar o tokenizer padrão do nltk. Portanto, exemplos como does n'tnão lematizar para do not.
port.stem("this")produz thie port.stem("was") wa, mesmo quando a posição certa é fornecida para cada um.
A página oficial de Martin Porter contém um Porter Stemmer em PHP e outras linguagens .
Se você realmente quer uma boa lematização, vai precisar começar com algo como o Algoritmo de Porter, refine-o adicionando regras para corrigir casos incorretos comuns ao seu conjunto de dados e, finalmente, adicione muitas exceções às regras . Isso pode ser facilmente implementado com pares de chave / valor (dbm / hash / dicionários) onde a chave é a palavra a ser pesquisada e o valor é a palavra raiz para substituir o original. Um mecanismo de pesquisa comercial em que trabalhei uma vez acabou com 800 algumas exceções a um algoritmo de Porter modificado.
http://wordnet.princeton.edu/man/morph.3WN
Para muitos dos meus projetos, prefiro o lematizador WordNet baseado em léxico em vez do lematizador Porter mais agressivo.
http://wordnet.princeton.edu/links#PHP tem um link para uma interface PHP para as APIs WN.
Com base em várias respostas no Stack Overflow e em blogs que encontrei, este é o método que estou usando e parece retornar palavras reais muito bem. A ideia é dividir o texto recebido em uma série de palavras (use o método que desejar) e, em seguida, encontrar as classes gramaticais (POS) para essas palavras e usá-las para ajudar a drenar e lematizar as palavras.
Sua amostra acima não funciona muito bem, porque o POS não pode ser determinado. No entanto, se usarmos uma frase real, as coisas funcionam muito melhor.
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', '.']
Procure no WordNet, um grande banco de dados lexical para o idioma inglês:
Existem APIs para acessá-lo em vários idiomas.
Parece interessante: MIT Java WordnetStemmer: http://projects.csail.mit.edu/jwi/api/edu/mit/jwi/morph/WordnetStemmer.html
Dê uma olhada no LemmaGen - biblioteca de código aberto escrita em C # 3.0.
Resultados para suas palavras de teste ( http://lemmatise.ijs.si/Services )
Os pacotes de topo Python (em nenhuma ordem específica) para lematização são: spacy, nltk, gensim, pattern, CoreNLPe TextBlob. Eu prefiro a implementação de spaCy e gensim (com base no padrão) porque eles identificam a marca POS da palavra e atribuem o lema apropriado automaticamente. O fornece lemas mais relevantes, mantendo o significado intacto.
Se você planeja usar nltk ou TextBlob, você precisa se preocupar em encontrar a tag POS certa manualmente e encontrar o lema certo.
Exemplo de lematização com spaCy:
# Run below statements in terminal once.
pip install spacy
spacy download en
import spacy
# Initialize spacy 'en' model
nlp = spacy.load('en', disable=['parser', 'ner'])
sentence = "The striped bats are hanging on their feet for best"
# Parse
doc = nlp(sentence)
# Extract the lemma
" ".join([token.lemma_ for token in doc])
#> 'the strip bat be hang on -PRON- foot for good'
Exemplo de lematização com Gensim:
from gensim.utils import lemmatize
sentence = "The striped bats were hanging on their feet and ate best fishes"
lemmatized_out = [wd.decode('utf-8').split('/')[0] for wd in lemmatize(sentence)]
#> ['striped', 'bat', 'be', 'hang', 'foot', 'eat', 'best', 'fish']
Os exemplos acima foram emprestados desta página de lematização .
Faça uma pesquisa por Lucene, não tenho certeza se existe uma porta PHP, mas sei que Lucene está disponível para muitas plataformas. Lucene é uma biblioteca de indexação e pesquisa OSS (da Apache). Naturalmente, ele e os extras da comunidade podem ter algo interessante para observar. No mínimo você pode aprender como é feito em uma linguagem para que possa traduzir a "ideia" para PHP
Se eu puder citar minha resposta à pergunta que StompChicken mencionou:
A questão central aqui é que os algoritmos de lematização operam em uma base fonética, sem nenhuma compreensão real da linguagem com a qual estão trabalhando.
Como não entendem a língua e não fogem de um dicionário de termos, não têm como reconhecer e responder adequadamente aos casos irregulares, como "correu" / "correu".
Se precisar lidar com casos irregulares, você precisará escolher uma abordagem diferente ou aumentar sua lematização com seu próprio dicionário personalizado de correções para executar depois que o lematizador tiver feito seu trabalho.
A versão mais atual do lematizador em NLTK é Snowball.
Você pode encontrar exemplos de como usá-lo aqui:
http://nltk.googlecode.com/svn/trunk/doc/api/nltk.stem.snowball2-pysrc.html#demo
Você pode usar o lematizador Morpha. UW carregou morpha stemmer no Maven central se você planeja usá-lo em um aplicativo Java. Existe um invólucro que o torna muito mais fácil de usar. Você só precisa adicioná-lo como uma dependência e usar a edu.washington.cs.knowitall.morpha.MorphaStemmerclasse. As instâncias são threadsafe (o JFlex original tinha campos de classe para variáveis locais desnecessariamente). Instancie uma classe e execute morphaa palavra que deseja derivar.
new MorphaStemmer().morpha("climbed") // goes to "climb"
Martin Porter escreveu Snowball (uma linguagem para algoritmos de lematização) e reescreveu o "English Stemmer" em Snowball. Existe um Stemmer em inglês para C e Java.
Ele afirma explicitamente que o Porter Stemmer foi reimplementado apenas por razões históricas, portanto, testar a correção de stemming com o Porter Stemmer obterá resultados que você (deveria) já conhecer.
De http://tartarus.org/~martin/PorterStemmer/index.html (ênfase minha)
O lematizador Porter deve ser considerado ' congelado ', isto é, estritamente definido e não passível de modificações posteriores. Como lematizador, é ligeiramente inferior ao lematizador Snowball English ou Porter2, que deriva dele e que está sujeito a melhorias ocasionais. Para o trabalho prático, portanto, a nova haste do Snowball é recomendada. O stemmer Porter é apropriado para trabalho de pesquisa de IR envolvendo stemming onde os experimentos precisam ser exatamente repetidos.
Dr. Porter sugere usar o lematizador inglês ou Porter2 em vez do lematizador Porter. O lematizador em inglês é o que realmente é usado no site de demonstração, como @StompChicken respondeu anteriormente.
Em Java, eu uso tartargus-snowball para derivar palavras
Maven:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-snowball</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>
Código de amostra:
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
}
Experimente este aqui: http://www.twinword.com/lemmatizer.php
Entrei sua consulta no demo "cats running ran cactus cactuses cacti community communities"e obtive ["cat", "running", "run", "cactus", "cactus", "cactus", "community", "community"]com o flag opcional ALL_TOKENS.
Código de amostra
Esta é uma API para que você possa se conectar a ela de qualquer ambiente. Esta é a aparência da chamada 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"
)
);
Eu recomendo fortemente o uso de Spacy (análise e marcação de texto base) e Textacy (processamento de texto de nível superior construído em cima do Spacy).
Palavras lematizadas estão disponíveis por padrão no Spacy como um .lemma_atributo de token e o texto pode ser lematizado ao fazer muitos outros pré-processamento de texto com textacy. Por exemplo, ao criar um pacote de termos ou palavras ou, geralmente, antes de executar algum processamento que o exija.
Recomendo que você verifique os dois antes de escrever qualquer código, pois isso pode economizar muito tempo!
df_plots = pd.read_excel("Plot Summary.xlsx", index_col = 0)
df_plots
# Printing first sentence of first row and last sentence of last row
nltk.sent_tokenize(df_plots.loc[1].Plot)[0] + nltk.sent_tokenize(df_plots.loc[len(df)].Plot)[-1]
# Calculating length of all plots by words
df_plots["Length"] = df_plots.Plot.apply(lambda x :
len(nltk.word_tokenize(x)))
print("Longest plot is for season"),
print(df_plots.Length.idxmax())
print("Shortest plot is for season"),
print(df_plots.Length.idxmin())
#What is this show about? (What are the top 3 words used , excluding the #stop words, in all the #seasons combined)
word_sample = list(["struggled", "died"])
word_list = nltk.pos_tag(word_sample)
[wnl.lemmatize(str(word_list[index][0]), pos = word_list[index][1][0].lower()) for index in range(len(word_list))]
# Figure out the stop words
stop = (stopwords.words('english'))
# Tokenize all the plots
df_plots["Tokenized"] = df_plots.Plot.apply(lambda x : nltk.word_tokenize(x.lower()))
# Remove the stop words
df_plots["Filtered"] = df_plots.Tokenized.apply(lambda x : (word for word in x if word not in stop))
# Lemmatize each word
wnl = WordNetLemmatizer()
df_plots["POS"] = df_plots.Filtered.apply(lambda x : nltk.pos_tag(list(x)))
# df_plots["POS"] = df_plots.POS.apply(lambda x : ((word[1] = word[1][0] for word in word_list) for word_list in x))
df_plots["Lemmatized"] = df_plots.POS.apply(lambda x : (wnl.lemmatize(x[index][0], pos = str(x[index][1][0]).lower()) for index in range(len(list(x)))))
#Which Season had the highest screenplay of "Jesse" compared to "Walt"
#Screenplay of Jesse =(Occurences of "Jesse")/(Occurences of "Jesse"+ #Occurences of "Walt")
df_plots.groupby("Season").Tokenized.sum()
df_plots["Share"] = df_plots.groupby("Season").Tokenized.sum().apply(lambda x : float(x.count("jesse") * 100)/float(x.count("jesse") + x.count("walter") + x.count("walt")))
print("The highest times Jesse was mentioned compared to Walter/Walt was in season"),
print(df_plots["Share"].idxmax())
#float(df_plots.Tokenized.sum().count('jesse')) * 100 / #float((df_plots.Tokenized.sum().count('jesse') + #df_plots.Tokenized.sum().count('walt') + #df_plots.Tokenized.sum().count('walter')))