2009-04-21 34 views
93

Tôi đã thử PorterStemmer và Snowball nhưng cả hai đều không hoạt động trên tất cả các từ, thiếu một số từ rất phổ biến.Làm cách nào để thực hiện từ Stemming hoặc Lemmatization?

Từ thử nghiệm của tôi là: "mèo chạy xương rồng cactus cactus cộng đồng cộng đồng" và cả hai nhận được ít hơn một nửa bên phải.

Xem thêm:

+22

Đó không phải là xương rồng? – MSalters

+3

Chỉ cần tạo tham chiếu vòng tròn cho câu hỏi ban đầu được đăng trên Reddit: [Làm cách nào để lập trình bắt đầu? (ví dụ: "ăn" để "ăn", "cây xương rồng" để "cây xương rồng")] (http://www.reddit.com/r/programming/comments/8e5d3/how_do_i_programatically_do_stemming_eg_eating_to/) Đăng ở đây vì các nhận xét bao gồm thông tin hữu ích. –

+1

xem http://stackoverflow.com/questions/17317418/stemmers-vs-lemmatizers – alvas

Trả lời

1

Thực hiện tìm kiếm cho Lucene, im không chắc chắn nếu theres một cổng PHP nhưng tôi biết Lucene có sẵn cho nhiều nền tảng . Lucene là một thư viện lập chỉ mục và tìm kiếm của OSS (từ Apache). Đương nhiên nó và cộng đồng tính năng bổ sung có thể có một cái gì đó thú vị để xem xét. Ít nhất bạn có thể học cách thực hiện nó trong một ngôn ngữ, do đó bạn có thể dịch là "ý tưởng" vào PHP

24

tôi đã cố gắng danh sách thuật ngữ trên this snowball demo site và kết quả tìm kiếm được rồi ....

  • mèo -> mèo
  • chạy -> chạy
  • chạy -> chạy
  • cây xương rồng -> xương rồng
  • cây xương rồng -> xương rồng
  • cộng đồng -> communiti
  • cộng đồng -> communiti

Một Stemmer là nghĩa vụ phải chuyển hình thức biến cách của từ xuống một số gốc chung. Nó không thực sự là công việc của một người gốc để làm cho gốc đó trở thành một từ điển 'thích hợp'. Cho rằng bạn cần phải xem morphological/orthographic analysers.

Tôi nghĩ rằng this question là về nhiều hơn hoặc ít hơn cùng một điều, và câu trả lời của Kaarel cho câu hỏi đó là nơi tôi lấy liên kết thứ hai từ.

+0

Không ấn tượng sau lần thử nghiệm đầu tiên 'cập nhật -> updat' – Medorator

+3

Vấn đề là gốc (" cập nhật ") == gốc (" cập nhật "), mà nó làm (update -> updat) – Stompchicken

+0

Phần mềm có thể làm gốc (x) == gốc (y) nhưng điều đó không trả lời câu hỏi hoàn toàn – Medorator

8

Trang chính thức của Martin Porter chứa Porter Stemmer in PHP cũng như other languages.

Nếu bạn thực sự nghiêm túc về việc khởi đầu tốt mặc dù bạn cần bắt đầu với thuật toán Porter, hãy tinh chỉnh nó bằng cách thêm quy tắc để sửa các trường hợp không chính xác chung cho tập dữ liệu của bạn, và cuối cùng thêm rất nhiều ngoại lệ cho các quy tắc. Điều này có thể dễ dàng thực hiện với các cặp khóa/giá trị (dbm/hash/từ điển) trong đó khóa là từ cần tra cứu và giá trị là từ gốc để thay thế bản gốc. Một công cụ tìm kiếm thương mại tôi đã làm việc trên một lần kết thúc với 800 một số ngoại lệ cho một thuật toán Porter sửa đổi.

+0

Một giải pháp lý tưởng sẽ tự động tìm hiểu những kỳ vọng này. Bạn đã có kinh nghiệm với một hệ thống như vậy chưa? – Malcolm

+0

Không. Trong trường hợp của chúng tôi các tài liệu được lập chỉ mục là mã và quy định cho một khu vực cụ thể của pháp luật và có hàng chục (người) biên tập phân tích các chỉ mục cho bất kỳ thân cây xấu nào. –

1

Nếu tôi có thể trích dẫn câu trả lời của tôi cho câu hỏi StompChicken đề cập:

Vấn đề cốt lõi ở đây là thuật toán bắt nguồn hoạt động trên cơ sở ngữ âm không có sự hiểu biết thực tế của ngôn ngữ mà họ đang sử dụng.

Vì họ không hiểu ngôn ngữ và không chạy từ điển cụm từ, họ không có cách nào nhận ra và trả lời thích hợp cho các trường hợp bất thường, chẳng hạn như "chạy"/"chạy".

Nếu bạn cần xử lý các trường hợp bất thường, bạn sẽ cần phải chọn một cách tiếp cận khác hoặc tăng cường bắt đầu bằng từ điển tùy chỉnh của riêng bạn để chạy sau khi trình tạo gốc đã thực hiện.

3

Nhìn vào WordNet, một cơ sở dữ liệu từ vựng lớn cho ngôn ngữ tiếng Anh:

http://wordnet.princeton.edu/

Có API để truy cập nó trong một số ngôn ngữ.

123

Nếu bạn biết Python, Natural Language Toolkit (NLTK) có trình tối ưu hóa rất mạnh mẽ, sử dụng WordNet.

Lưu ý rằng nếu bạn đang sử dụng lemmatizer này lần đầu tiên, bạn phải tải xuống kho trước khi sử dụng nó. Điều này có thể được thực hiện bởi:

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

Bạn chỉ phải thực hiện việc này một lần. Giả sử bây giờ bạn đã tải về các corpus, nó hoạt động như thế này:

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

Có lemmatizers khác trong nltk.stem module, nhưng tôi đã không cố gắng họ bản thân mình.

+7

Oh buồn ... trước khi tôi biết tìm kiếm S.O. Tôi đã tự thực hiện! – Crisfole

+10

Đừng quên cài đặt kho văn bản trước khi sử dụng ** nltk ** lần đầu tiên! http://www.velvetcache.org/2010/03/01/looking-up-words-in-a-dictionary-using-python –

+1

Vâng, điều này sử dụng một số thuật toán không xác định như Porter Stemmer, nếu bạn thử nó với 'chết', nó cho bạn' dy' thay vì 'chết'. Không phải là có một số loại từ điển gốc cứng nhắc? – SexyBeast

0

.Net lucene có trình cắm gốc porter sẵn có. Bạn có thể thử điều đó. Nhưng lưu ý rằng porter xuất phát không xem xét ngữ cảnh từ khi phát sinh bổ đề. (Đi qua thuật toán và triển khai thuật toán của nó và bạn sẽ thấy cách nó hoạt động)

28

Tôi sử dụng stanford nlp để thực hiện lemmatization. Tôi đã bị mắc kẹt với một vấn đề tương tự trong vài ngày qua. Tất cả nhờ vào stackoverflow để giúp tôi giải quyết vấn đề.

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); 
      } 
     } 
    } 
} 

Cũng nên sử dụng các từ dừng để giảm thiểu các lemma đầu ra nếu nó được sử dụng sau này trong bộ phân loại. Vui lòng xem coreNlp phần mở rộng được viết bởi John Conwell.

+0

xin lỗi vì trả lời trễ .. tôi đã nhận được sự cố này chỉ được giải quyết ngay bây giờ! :) – CTsiddharth

+1

Dòng 'pipeline = new ...' không biên dịch cho tôi. Nếu tôi thay đổi nó thành 'StanfordCoreNLP pipelne = new ...' nó biên dịch. Os này đúng không? –

+0

Có, trước tiên bạn phải khai báo đường ống var. NLP của Stanford cũng có thể được sử dụng từ dòng lệnh để bạn không phải làm bất kỳ chương trình nào, bạn chỉ cần tạo tệp thuộc tính và nạp các tệp thực thi với nó. Đọc tài liệu: http://nlp.stanford.edu/software/corenlp.shtml –

1

Bạn có thể sử dụng Stemmer Morpha. UW có uploaded morpha stemmer to Maven central nếu bạn định sử dụng nó từ một ứng dụng Java. Có một wrapper mà làm cho nó dễ dàng hơn nhiều để sử dụng. Bạn chỉ cần thêm nó làm phụ thuộc và sử dụng lớp edu.washington.cs.knowitall.morpha.MorphaStemmer. Các cá thể là luồng an toàn (bản gốc JFlex có các trường lớp cho các biến cục bộ không cần thiết). Khởi tạo một lớp và chạy morpha và từ bạn muốn bắt đầu.

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

này có vẻ thú vị: MIT Java WordnetStemmer: http://projects.csail.mit.edu/jwi/api/edu/mit/jwi/morph/WordnetStemmer.html

+3

Chào mừng bạn đến với SO và cảm ơn bài đăng của bạn, +1. Nó sẽ là tuyệt vời nếu bạn có thể làm cho một vài ý kiến ​​về cách sử dụng của stemmer này, hiệu suất vv Chỉ cần một liên kết thường không được coi là một câu trả lời rất tốt. – jogojapan

0

Martin Porter đã viết Snowball (một ngôn ngữ cho bắt nguồn thuật toán) và viết lại "tiếng Anh Stemmer" trong Snowball. Có một Stemmer tiếng Anh cho C và Java.

Ông tuyên bố rõ ràng rằng Porter Stemmer đã được thực hiện lại chỉ vì lý do lịch sử, do đó kiểm tra tính chính xác đối với Porter Stemmer sẽ mang lại kết quả mà bạn (nên) đã biết.

Từ http://tartarus.org/~martin/PorterStemmer/index.html (tôi nhấn mạnh)

Các Porter Stemmer nên được coi là ‘đông lạnh’, nghĩa là, đúng quy định, và không tuân theo chỉnh sửa thêm. Là một thân cây, nó hơi kém hơn so với trình phát gốc Snowball English hoặc Porter2, xuất phát từ nó, và được cải thiện không thường xuyên. Đối với công việc thực tế, do đó, các gốc mới Snowball được khuyến khích. Thân cây Porter thích hợp với công việc nghiên cứu IR liên quan đến xuất phát nơi các thí nghiệm cần được lặp lại chính xác.

Tiến sĩ Porter đề xuất sử dụng trình phát gốc tiếng Anh hoặc Porter2 thay vì trình tạo gốc Porter. Các stemmer tiếng Anh là những gì thực sự được sử dụng trong demo site như @StompChicken đã trả lời trước đó.

16

Các cuộc tranh luận về vấn đề gốc sinh sản và lemmatizer diễn ra. Đó là vấn đề thích độ chính xác hơn hiệu quả. Bạn nên lemmatize để đạt được các đơn vị ngôn ngữ có ý nghĩa và bắt nguồn từ sử dụng nước ép máy tính tối thiểu và vẫn chỉ mục một từ và các biến thể của nó dưới cùng một khóa.

Xem Stemmers vs Lemmatizers

Dưới đây là một ví dụ với 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' 
+1

Như đã đề cập ở trên, 'lemmatize()' của WordNetLemmatizer' có thể lấy thẻ POS. Vì vậy, từ ví dụ của bạn: '" ".join ([wnl.lemmatize (i, pos = VERB) cho i trong sent.split()])' cho ''cat run run cactus cactuses cacti community community''. –

+0

@NickRuiz, tôi nghĩ bạn có nghĩa là 'pos = NOUN'? BTW: Thời gian dài không nhìn thấy, hy vọng chúng tôi sẽ gặp nhau trong hội nghị sớm =) – alvas

+0

thực sự, không (Hy vọng rằng 'có' để hội nghị, mặc dù). Bởi vì nếu bạn đặt 'pos = VERB' bạn chỉ làm lemmatization trên động từ. Các danh từ vẫn giữ nguyên. Tôi chỉ phải viết một số mã của riêng tôi để xoay quanh các thẻ POS Treebank của Penn thực tế để áp dụng chính xác lemmatization cho mỗi mã thông báo. Ngoài ra, 'WordNetLemmatizer' stinks tại lemmatizing tokenization mặc định của nltk. Vì vậy, ví dụ như 'does n't' không lemmatize để' không'. –

2

Hãy xem LemmaGen - thư viện mã nguồn mở viết bằng C# 3.0.

Kết quả cho từ thử nghiệm của bạn (http://lemmatise.ijs.si/Services)

  • mèo -> mèo
  • chạy
  • chạy -> chạy
  • xương rồng
  • cây xương rồng -> xương rồng
  • xương rồng -> cây xương rồng
  • cộng đồng
  • cộng đồng -> cộng đồng
0

Trong Java, tôi sử dụng tartargus-snowball lời bắt nguồn

Maven: Mã

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

mẫu:

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

Hãy thử điều này một ở đây: http://www.twinword.com/lemmatizer.php

Tôi đã nhập truy vấn của bạn trong bản demo "cats running ran cactus cactuses cacti community communities" và nhận ["cat", "running", "run", "cactus", "cactus", "cactus", "community", "community"] bằng cờ tùy chọn ALL_TOKENS.

Mẫu Mã

Đây là một API để bạn có thể kết nối với nó từ bất kỳ môi trường. Đây là những gì các cuộc gọi PHP REST có thể giống như thế.

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

Dựa trên các câu trả lời khác nhau trên Stack Overflow và blog tôi đã gặp, đây là phương pháp tôi đang sử dụng và dường như trả lại các từ thực sự khá tốt. Ý tưởng là chia văn bản vào thành một mảng các từ (sử dụng phương pháp nào bạn muốn), và sau đó tìm các phần của lời nói (POS) cho những từ đó và sử dụng để giúp ngăn chặn và lemmatize các từ.

Bạn mẫu ở trên không hoạt động tốt, vì không thể xác định POS. Tuy nhiên, nếu chúng ta sử dụng một câu thật, mọi thứ sẽ hoạt động tốt hơn nhiều.

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', '.'] 
Các vấn đề liên quan