私はPorterStemmerとSnowballを試してみましたが、どちらもすべての単語に対して機能するわけではなく、非常に一般的な単語がいくつかありません。
私のテストの言葉は、「走っているサボテンサボテンサボテンコミュニティコミュニティを実行している猫」で、どちらも半分以下しか正しくありません。
以下も参照してください。
私はPorterStemmerとSnowballを試してみましたが、どちらもすべての単語に対して機能するわけではなく、非常に一般的な単語がいくつかありません。
私のテストの言葉は、「走っているサボテンサボテンサボテンコミュニティコミュニティを実行している猫」で、どちらも半分以下しか正しくありません。
以下も参照してください。
回答:
Pythonを知っている場合、The Natural Language Toolkit(NLTK)には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'
nltk.stemモジュールには他のレマタイザがありますが、私はそれらを自分で試していません。
dies
、それはあなたを与えるdy
代わりにdie
。何らかのハードコードされたステマー辞書はありませんか?
WordNetLemmatizer
誤って見出し語化する単語は何ですか?
スタンマト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);
}
}
}
}
また、後で分類子で使用する場合は、ストップワードを使用して出力見出しを最小化することをお勧めします。John Conwellによって作成されたcoreNlp拡張機能をご覧ください。
私はこのスノーボールデモサイトで用語のリストを試してみましたが、結果は問題ありません。
ステマーは、活用形の単語をいくつかの一般的な語根に変えることになっています。そのルートを「適切な」辞書の単語にすることは、ステマーの仕事ではありません。そのためには、形態学的/正書法アナライザーを調べる必要があります。
この質問は多かれ少なかれ同じことに関するものだと私は思います。その質問に対するカーレルの答えは、私が2番目のリンクを取得した場所です。
ステマー対レンマタイザの議論は続いています。効率よりも精度を優先することが問題です。言語学的に意味のある単位を達成するために見出し語を付け、最小限の計算能力を使用し、同じキーの下で単語とそのバリエーションを索引付けするようにステムする必要があります。
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
さんは、lemmatize()
POSタグを取ることができます。だからあなたの例から:" ".join([wnl.lemmatize(i, pos=VERB) for i in sent.split()])
を与え'cat run run cactus cactuses cacti community communities'
ます。
pos=NOUN
か?ところで:久しぶりです。うまくいけば、すぐに会議でお互いに会う予定です=)
pos=VERB
場合、動詞の見出し語化だけを行うからです。名詞は変わりません。実際のペンツリーバンクのPOSタグを軸にして独自のコードを記述し、各トークンに正しい見出し語を適用する必要がありました。また、WordNetLemmatizer
nltkのデフォルトのトークナイザーの扱いを悪用しています。したがって、のような例does n't
はにlemmatizeしませんdo not
。
port.stem("this")
生産thi
とport.stem("was")
wa
右のPOSは、それぞれのために提供された場合でも、。
Martin Porterの公式ページには、PHPや他の言語のPorter Stemmerが含まれています。
ポーターアルゴリズムのようなものから始める必要があるが、適切なステミングに真剣に取り組んでいる場合は、ルールを追加してデータセットに共通の誤ったケースを修正し、最後に多くの例外をルールに追加する。これは、キーと値のペア(dbm / hash / dictionaries)で簡単に実装できます。キーは検索する単語で、値は元の単語を置き換える語幹の単語です。かつて私が取り組んだ商用検索エンジンは、変更されたポーターアルゴリズムに対して800の例外をいくつか抱えていました。
http://wordnet.princeton.edu/man/morph.3WN
私の多くのプロジェクトでは、より積極的なポーターステミングよりも、辞書ベースのWordNet lemmatizerを好みます。
http://wordnet.princeton.edu/links#PHPには、WN APIへのPHPインターフェイスへのリンクがあります。
Stack Overflowや私が出会ったブログに関するさまざまな回答に基づいて、これは私が使用している方法であり、実際の単語を非常によく返すようです。着信テキストを単語の配列に分割し(どの方法を使用してもかまいません)、それらの単語の品詞(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', '.']
これは興味深いようです:MIT Java WordnetStemmer:http ://projects.csail.mit.edu/jwi/api/edu/mit/jwi/morph/WordnetStemmer.html
LemmaGen -C#3.0で記述されたオープンソースライブラリをご覧ください。
テストワードの結果(http://lemmatise.ijs.si/Services)
:見出し語処理のためのトップのpythonパッケージ(なし特定の順序では)あるspacy
、nltk
、gensim
、pattern
、CoreNLP
とTextBlob
。spaCyとgensimの実装(パターンに基づく)を好むのは、単語のPOSタグを識別し、適切な補題を自動的に割り当てるからです。は意味を損なわずに、より適切な補題を提供します。
nltkまたはTextBlobを使用する予定の場合は、手動で適切なPOSタグを見つけ、適切な補題を見つける必要があります。
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'
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']
StompChickenが述べた質問への私の答えを引用する場合:
ここでの中心的な問題は、ステミングアルゴリズムが音声ベースで動作し、使用している言語を実際に理解していないことです。
彼らは言語を理解しておらず、用語の辞書から実行されないため、「実行」/「実行」などの不規則なケースを認識して適切に対応する方法がありません。
不規則なケースを処理する必要がある場合は、別のアプローチを選択するか、ステマーが処理を行った後に実行する独自のカスタム修正辞書でステミングを拡張する必要があります。
NLTKのステマーの最新バージョンはSnowballです。
あなたはそれをここで使用する方法の例を見つけることができます:
http://nltk.googlecode.com/svn/trunk/doc/api/nltk.stem.snowball2-pysrc.html#demo
Morphaステマーを使用できます。UWは、モーファステマーを Javaアプリケーションから使用する場合、Mavenセントラルにアップロードしました。使いやすくするラッパーがあります。依存関係として追加し、edu.washington.cs.knowitall.morpha.MorphaStemmer
クラスを使用するだけです。インスタンスはスレッドセーフです(元のJFlexには、不必要にローカル変数のクラスフィールドがありました)。クラスをインスタンス化して実行morpha
し、語幹処理したい単語を実行します。
new MorphaStemmer().morpha("climbed") // goes to "climb"
Martin PorterはSnowball(ステミングアルゴリズムの言語)を書き、Snowballで「English Stemmer」を書き直しました。CとJavaには英語のステマーがあります。
彼は、Porter Stemmerが歴史的な理由でのみ再実装されたと明確に述べているため、Porter Stemmerに対してステミングの正しさをテストすると、すでに知っているはずの結果が得られます。
http://tartarus.org/~martin/PorterStemmer/index.html(強調鉱山)
ポーターステマーは「冷凍」、つまり厳密に定義されたものと見なされ、それ以上の変更はできません。ステマーとしては、Snowball EnglishまたはPorter2ステマーよりわずかに劣っています。これは、それから派生し、時折改善されます。したがって、実際の作業では、新しいSnowballステマーが推奨されます。Porterステマーは、実験を正確に繰り返す必要があるステミングを含むIR研究作業に適しています。
ポーター博士は、ポーターステマーの代わりに英語またはポーター2ステマーを使用することを提案しています。英語のステマーは、@ StompChickenが以前に回答したように、デモサイトで実際に使用されているものです。
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
}
これをここで試してください: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"
)
);
Spacy(ベーステキストの解析とタグ付け)とTextacy(Spacyの上に構築された高レベルのテキスト処理)を使用することを強くお勧めします。
レンマ化された単語は、デフォルトでトークンの.lemma_
属性としてSpacyで利用可能であり、テキストは、textacyで他の多くのテキスト前処理を行っている間にレンマ化できます。たとえば、用語 や単語のバッグを作成しているとき、または一般的にそれを必要とする処理を実行する直前。
コードを書く前に両方をチェックすることをお勧めします。これにより、多くの時間を節約できる可能性があります。
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')))