ฉันได้ลอง PorterStemmer และ Snowball แล้ว แต่ทั้งคู่ใช้ไม่ได้กับทุกคำขาดคำที่ใช้บ่อยมาก
คำทดสอบของฉันคือ: " cat running ran cactus cactuses cacti community community " และทั้งสองได้รับสิทธิน้อยกว่าครึ่งหนึ่ง
ดูสิ่งนี้ด้วย:
ฉันได้ลอง PorterStemmer และ Snowball แล้ว แต่ทั้งคู่ใช้ไม่ได้กับทุกคำขาดคำที่ใช้บ่อยมาก
คำทดสอบของฉันคือ: " cat running ran cactus cactuses cacti community community " และทั้งสองได้รับสิทธิน้อยกว่าครึ่งหนึ่ง
ดูสิ่งนี้ด้วย:
คำตอบ:
ถ้าคุณรู้จัก Python Natural Language Toolkit (NLTK)มี lemmatizer ที่ทรงพลังมากที่ใช้ประโยชน์จาก 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'
มี lemmatizers อื่น ๆ ในโมดูล nltk.stemแต่ฉันยังไม่ได้ลองด้วยตัวเอง
dies
จะช่วยให้คุณแทนdy
die
ไม่มีพจนานุกรม Stemmer แบบเข้ารหัสบางประเภทหรือไม่?
WordNetLemmatizer
สะกดผิด
ฉันใช้stanford nlpในการทำ lemmatization ฉันจมอยู่กับปัญหาที่คล้ายกันในช่วงสองสามวันที่ผ่านมา ขอขอบคุณ 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 ที่เขียนโดย John Conwell
ฉันลองใช้รายการคำศัพท์ของคุณในไซต์สาธิตก้อนหิมะนี้และผลลัพธ์ก็ดูโอเค ....
Stemmer ควรเปลี่ยนรูปแบบของคำที่ผันแปรเป็นรูททั่วไป ไม่ใช่งานของผู้ควบคุมที่จะทำให้รูทนั้นเป็นคำศัพท์ที่ 'เหมาะสม' ในพจนานุกรม สำหรับสิ่งนั้นคุณต้องดูที่เครื่องวิเคราะห์ทางสัณฐานวิทยา / ออร์โธกราฟิกวิเคราะห์
ฉันคิดว่าคำถามนี้เกี่ยวกับสิ่งเดียวกันไม่มากก็น้อยและคำตอบของ Kaarel สำหรับคำถามนั้นคือที่ที่ฉันเอาลิงค์ที่สองมาจาก
การถกเถียงกันของ stemmer กับ lemmatizer ดำเนินต่อไป เป็นเรื่องของการเลือกใช้ความแม่นยำมากกว่าประสิทธิภาพ คุณควรทำให้เป็นตัวย่อเพื่อให้ได้หน่วยและต้นกำเนิดที่มีความหมายทางภาษาเพื่อใช้น้ำผลไม้ในการคำนวณน้อยที่สุดและยังคงจัดทำดัชนีคำและรูปแบบต่างๆภายใต้คีย์เดียวกัน
นี่คือตัวอย่างของ 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()
สามารถใช้แท็ก POS ดังนั้นจากตัวอย่างของคุณ: ให้" ".join([wnl.lemmatize(i, pos=VERB) for i in sent.split()])
'cat run run cactus cactuses cacti community communities'
pos=NOUN
? BTW: ไม่ได้เจอกันนานหวังว่าเราจะได้พบกันในการประชุมเร็ว ๆ นี้ =)
pos=VERB
คุณทำแค่คำนามที่เป็นคำกริยา คำนามยังคงเหมือนเดิม ฉันต้องเขียนโค้ดของตัวเองเพื่อหมุนรอบแท็ก POS ของ Penn Treebank จริงเพื่อใช้การสะกดคำที่ถูกต้องกับโทเค็นแต่ละรายการ นอกจากนี้ยังมีWordNetLemmatizer
กลิ่นเหม็นที่โทเค็นไนเซอร์เริ่มต้นของ nltk ดังนั้นตัวอย่างชอบdoes n't
ไม่ lemmatize do not
ไป
port.stem("this")
ผลิตthi
และport.stem("was")
wa
แม้ว่าจะมีการจัดเตรียมตำแหน่งที่เหมาะสมสำหรับแต่ละคน
หน้าอย่างเป็นทางการของ Martin Porter มีPorter Stemmer ใน PHPและภาษาอื่น ๆภาษาอื่น
หากคุณจริงจังกับการหยุดชะงักที่ดีแม้ว่าคุณจะต้องเริ่มต้นด้วยอะไรบางอย่างเช่นอัลกอริทึม Porter ให้ปรับแต่งโดยเพิ่มกฎเพื่อแก้ไขกรณีที่ไม่ถูกต้องที่พบบ่อยในชุดข้อมูลของคุณจากนั้นจึงเพิ่มข้อยกเว้นจำนวนมากให้กับกฎ . สิ่งนี้สามารถใช้งานได้อย่างง่ายดายด้วยคู่คีย์ / ค่า (dbm / แฮช / พจนานุกรม) โดยที่คีย์คือคำที่ต้องการค้นหาและค่าคือคำที่เกิดขึ้นเพื่อแทนที่ต้นฉบับ เครื่องมือค้นหาเชิงพาณิชย์ที่ฉันทำงานครั้งหนึ่งลงเอยด้วย 800 ข้อยกเว้นบางประการสำหรับอัลกอริทึม Porter ที่ได้รับการแก้ไข
http://wordnet.princeton.edu/man/morph.3WN
สำหรับโครงการจำนวนมากของฉันฉันชอบคำศัพท์ WordNet lemmatizer มากกว่าคำว่า porter ที่ก้าวร้าวมากขึ้น
http://wordnet.princeton.edu/links#PHPมีลิงก์ไปยังอินเทอร์เฟซ PHP ไปยัง WN API
จากคำตอบต่างๆใน 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', '.']
ดู WordNet ฐานข้อมูลคำศัพท์ขนาดใหญ่สำหรับภาษาอังกฤษ:
มี API สำหรับการเข้าถึงในหลายภาษา
สิ่งนี้ดูน่าสนใจ: 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 )
แพคเกจด้านบนหลาม (ในลำดับที่เฉพาะเจาะจงไม่ได้) สำหรับ lemmatization คือ: spacy
, nltk
, gensim
, pattern
, CoreNLP
และTextBlob
และฉันชอบการใช้งานของ spaCy และ gensim (ตามรูปแบบ) เพราะพวกเขาระบุแท็ก POS ของคำและกำหนดคำหลักที่เหมาะสมโดยอัตโนมัติ ให้คำศัพท์ที่เกี่ยวข้องมากขึ้นโดยคงความหมายไว้ครบถ้วน
หากคุณวางแผนที่จะใช้ nltk หรือ TextBlob คุณต้องดูแลค้นหาแท็ก POS ที่ถูกต้องด้วยตนเองและค้นหาคำศัพท์ที่ถูกต้อง
Lemmatization ตัวอย่างกับ 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'
ตัวอย่าง Lemmatization ด้วย 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']
ตัวอย่างข้างต้นยืมมาจากในหน้าการสร้างคำอธิบายนี้
ทำการค้นหาสำหรับ Lucene ฉันไม่แน่ใจว่ามีพอร์ต PHP หรือไม่ แต่ฉันรู้ว่า Lucene สามารถใช้ได้กับหลายแพลตฟอร์ม Lucene เป็น OSS (จาก Apache) การสร้างดัชนีและไลบรารีการค้นหา โดยปกติแล้วมันและความพิเศษของชุมชนอาจมีอะไรที่น่าสนใจให้ดู อย่างน้อยที่สุดคุณสามารถเรียนรู้วิธีการทำงานในภาษาเดียวเพื่อให้คุณสามารถแปล "ความคิด" เป็น PHP ได้
หากฉันสามารถอ้างคำตอบของฉันสำหรับคำถามที่ StompChicken กล่าวถึง:
ปัญหาหลักที่นี่คืออัลกอริทึมการสะกดคำทำงานบนพื้นฐานการออกเสียงโดยไม่เข้าใจภาษาที่ใช้งานได้จริง
เนื่องจากพวกเขาไม่มีความเข้าใจในภาษาและไม่ได้เรียกใช้จากพจนานุกรมคำศัพท์พวกเขาจึงไม่มีทางจดจำและตอบสนองอย่างเหมาะสมกับกรณีที่ไม่ปกติเช่น "run" / "ran"
หากคุณต้องการจัดการกับกรณีที่ผิดปกติคุณจะต้องเลือกวิธีการอื่นหรือเพิ่มขีด จำกัด ของคุณด้วยพจนานุกรมการแก้ไขที่กำหนดเองของคุณเพื่อให้ทำงานหลังจากที่ Stemmer ทำสิ่งนั้นเสร็จแล้ว
Stemmer เวอร์ชันล่าสุดใน NLTK คือ Snowball
คุณสามารถดูตัวอย่างวิธีการใช้งานได้ที่นี่:
http://nltk.googlecode.com/svn/trunk/doc/api/nltk.stem.snowball2-pysrc.html#demo
คุณสามารถใช้ Morpha stemmer UW ได้อัปโหลด morpha stemmer ไปยัง Maven centralหากคุณวางแผนที่จะใช้จากแอปพลิเคชัน Java มีกระดาษห่อหุ้มที่ช่วยให้ใช้งานได้ง่ายขึ้นมาก คุณเพียงแค่ต้องเพิ่มเป็นข้อมูลอ้างอิงและใช้edu.washington.cs.knowitall.morpha.MorphaStemmer
คลาส อินสแตนซ์เป็นเธรดที่ปลอดภัย (JFlex ดั้งเดิมมีฟิลด์คลาสสำหรับตัวแปรโลคัลโดยไม่จำเป็น) สร้างชั้นเรียนและเรียกใช้morpha
และคำที่คุณต้องการเรียก
new MorphaStemmer().morpha("climbed") // goes to "climb"
. Net lucene มีสเตมเมอร์ลูกหาบในตัว คุณสามารถลองได้ แต่โปรดทราบว่า porter stemming ไม่พิจารณาบริบทของคำเมื่อได้มาจากคำหลัก (อ่านอัลกอริทึมและการนำไปใช้งานแล้วคุณจะเห็นว่ามันทำงานอย่างไร)
Martin Porter เขียน Snowball (ภาษาสำหรับอัลกอริธึมการสะกดคำ) และเขียน "English Stemmer" ใน Snowball มี Stemmer ภาษาอังกฤษสำหรับ C และ Java
เขาอย่างชัดเจนว่าพอร์เตอร์ Stemmer ได้รับ reimplemented เพียงด้วยเหตุผลทางประวัติศาสตร์ดังนั้นการทดสอบความถูกต้องที่เกิดกับพอร์เตอร์ Stemmer คุณจะได้รับผลที่คุณ (ควร) รู้อยู่แล้วว่า
จากhttp://tartarus.org/~martin/PorterStemmer/index.html (เน้นของฉัน)
Porter Stemmer ควรถือเป็น ' แช่แข็ง ' ซึ่งกำหนดไว้อย่างเคร่งครัดและไม่สามารถปรับเปลี่ยนเพิ่มเติมได้ ในฐานะสเตมเมอร์มันด้อยกว่าสเตมเมอร์ Snowball English หรือ Porter2 เล็กน้อยซึ่งมาจากมันและอาจมีการปรับปรุงเป็นครั้งคราว สำหรับการใช้งานจริงจึงขอแนะนำ Snowball Stemmer ใหม่ Porter Stemmer เหมาะสำหรับงานวิจัย IR ที่เกี่ยวข้องกับการกำหนดจุดที่การทดลองต้องทำซ้ำได้ทุกประการ
Dr. Porter แนะนำให้ใช้สเต็มเมอร์ภาษาอังกฤษหรือ Porter2 แทน Porter Stemmer ต้นกำเนิดภาษาอังกฤษคือสิ่งที่ใช้จริงในไซต์สาธิตตามที่ @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)
โดยค่าเริ่มต้นคำที่เป็นตัวอักษรจะมีให้ใช้งานโดยค่าเริ่มต้นใน Spacyเนื่องจาก.lemma_
แอตทริบิวต์ของโทเค็นและข้อความสามารถใช้อักษรย่อได้ในขณะที่ดำเนินการประมวลผลข้อความล่วงหน้าด้วย 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')))