【问题标题】:wordnet lemmatization and pos tagging in pythonpython中的wordnet词形还原和pos标记
【发布时间】:2013-03-23 12:23:54
【问题描述】:

我想在 python 中使用 wordnet lemmatizer,我了解到默认的 pos 标记是 NOUN,并且它不会为动词输出正确的 lemma,除非 pos 标记明确指定为 VERB。

我的问题是,为了准确地执行上述词形还原,最好的方法是什么?

我使用nltk.pos_tag 进行了 pos 标记,但在将树库 pos 标签与 wordnet 兼容的 pos 标签集成时我迷失了。请帮忙

from nltk.stem.wordnet import WordNetLemmatizer
lmtzr = WordNetLemmatizer()
tagged = nltk.pos_tag(tokens)

我得到了 NN,JJ,VB,RB 中的输出标签。如何将这些更改为 wordnet 兼容标签?

我还必须使用标记语料库训练nltk.pos_tag(),还是可以直接在我的数据上使用它来评估?

【问题讨论】:

  • 确实是个好问题!

标签: python nltk wordnet lemmatization


【解决方案1】:

首先,你可以不用训练直接使用nltk.pos_tag()。 该函数将从文件中加载预训练的标记器。可以看到文件名 nltk.tag._POS_TAGGER:

nltk.tag._POS_TAGGER
>>> 'taggers/maxent_treebank_pos_tagger/english.pickle' 

因为它是使用 Treebank 语料库训练的,所以它也使用 Treebank tag set。

以下函数会将树库标签映射到 WordNet 词性名称:

from nltk.corpus import wordnet

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

然后您可以将返回值与 lemmatizer 一起使用:

from nltk.stem.wordnet import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize('going', wordnet.VERB)
>>> 'go'

在将返回值传递给 Lemmatizer 之前检查它,因为空字符串会给出 KeyError。

【讨论】:

  • 还记得卫星形容词 =) ADJ_SAT = 's' wordnet.princeton.edu/wordnet/man/wngloss.7WN.html
  • 'it' 在"I'm loving it." 字符串中的 pos 标签是'PRP'。该函数返回一个词形分析器不接受的空字符串并抛出一个KeyError。在这种情况下可以做什么?
  • 有谁知道处理整个文档的效率如何?
  • @ClockSlave:不要将空字符串放入词形还原器中。
  • @alvas 哪些树库标签应该映射到 ADJ_SAT WordNet 标签?
【解决方案2】:

如nltk.corpus.reader.wordnet的源代码(http://www.nltk.org/_modules/nltk/corpus/reader/wordnet.html)

#{ Part-of-speech constants
 ADJ, ADJ_SAT, ADV, NOUN, VERB = 'a', 's', 'r', 'n', 'v'
#}
POS_LIST = [NOUN, VERB, ADJ, ADV]

【讨论】:

  • 或更笼统地说:from nltk.corpus import wordnet;打印 wordnet._FILEMAP;
  • 为什么 ADJ_SAT 没有出现在 POST_LIST 中? ADJ_SAT 形容词有哪些例子?
  • ADJ_SAT 属于形容词集群。您可以在此处阅读有关如何排列形容词簇的更多信息:wordnet.princeton.edu/documentation/wngloss7wn
【解决方案3】:

转换步骤:Document->Sentences->Tokens->POS->Lemmas

import nltk
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet

#example text text = 'What can I say about this place. The staff of these restaurants is nice and the eggplant is not bad'

class Splitter(object):
    """
    split the document into sentences and tokenize each sentence
    """
    def __init__(self):
        self.splitter = nltk.data.load('tokenizers/punkt/english.pickle')
        self.tokenizer = nltk.tokenize.TreebankWordTokenizer()

    def split(self,text):
        """
        out : ['What', 'can', 'I', 'say', 'about', 'this', 'place', '.']
        """
        # split into single sentence
        sentences = self.splitter.tokenize(text)
        # tokenization in each sentences
        tokens = [self.tokenizer.tokenize(sent) for sent in sentences]
        return tokens


class LemmatizationWithPOSTagger(object):
    def __init__(self):
        pass
    def get_wordnet_pos(self,treebank_tag):
        """
        return WORDNET POS compliance to WORDENT lemmatization (a,n,r,v) 
        """
        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:
            # As default pos in lemmatization is Noun
            return wordnet.NOUN

    def pos_tag(self,tokens):
        # find the pos tagginf for each tokens [('What', 'WP'), ('can', 'MD'), ('I', 'PRP') ....
        pos_tokens = [nltk.pos_tag(token) for token in tokens]

        # lemmatization using pos tagg   
        # convert into feature set of [('What', 'What', ['WP']), ('can', 'can', ['MD']), ... ie [original WORD, Lemmatized word, POS tag]
        pos_tokens = [ [(word, lemmatizer.lemmatize(word,self.get_wordnet_pos(pos_tag)), [pos_tag]) for (word,pos_tag) in pos] for pos in pos_tokens]
        return pos_tokens

lemmatizer = WordNetLemmatizer()
splitter = Splitter()
lemmatization_using_pos_tagger = LemmatizationWithPOSTagger()

#step 1 split document into sentence followed by tokenization
tokens = splitter.split(text)

#step 2 lemmatization using pos tagger 
lemma_pos_token = lemmatization_using_pos_tagger.pos_tag(tokens)
print(lemma_pos_token)

【讨论】:

    【解决方案4】:

    您可以使用 python 默认字典创建地图,并利用词形分析器的默认标签是名词这一事实。

    from nltk.corpus import wordnet as wn
    from nltk.stem.wordnet import WordNetLemmatizer
    from nltk import word_tokenize, pos_tag
    from collections import defaultdict
    
    tag_map = defaultdict(lambda : wn.NOUN)
    tag_map['J'] = wn.ADJ
    tag_map['V'] = wn.VERB
    tag_map['R'] = wn.ADV
    
    text = "Another way of achieving this task"
    tokens = word_tokenize(text)
    lmtzr = WordNetLemmatizer()
    
    for token, tag in pos_tag(tokens):
        lemma = lmtzr.lemmatize(token, tag_map[tag[0]])
        print(token, "=>", lemma)
    

    【讨论】:

    • 要使这个答案自成一体,请记住 import wn: from nltk.corpus import wordnet as wn
    • @pragMATHiC,包括它。谢谢。
    【解决方案5】:

    @Suzana_K 正在工作。但是我有一些情况导致 KeyError 作为@Clock Slave 提到的。

    将树库标签转换为 Wordnet 标签

    from nltk.corpus import wordnet
    
    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 None # for easy if-statement 
    

    现在,只有当我们有 wordnet 标签时,我们才将 pos 输入到 lemmatize 函数中

    from nltk.stem.wordnet import WordNetLemmatizer
    lemmatizer = WordNetLemmatizer()
    tagged = nltk.pos_tag(tokens)
    for word, tag in tagged:
        wntag = get_wordnet_pos(tag)
        if wntag is None:# not supply tag in case of None
            lemma = lemmatizer.lemmatize(word) 
        else:
            lemma = lemmatizer.lemmatize(word, pos=wntag) 
    

    【讨论】:

      【解决方案6】:

      你可以这样做:

      import nltk
      from nltk.corpus import wordnet
      
      wordnet_map = {
          "N": wordnet.NOUN,
          "V": wordnet.VERB,
          "J": wordnet.ADJ,
          "R": wordnet.ADV
      }
      
      
      def pos_tag_wordnet(text):
          """
              Create pos_tag with wordnet format
          """
          pos_tagged_text = nltk.pos_tag(text)
      
          # map the pos tagging output with wordnet output
          pos_tagged_text = [
              (word, wordnet_map.get(pos_tag[0])) if pos_tag[0] in wordnet_map.keys()
              else (word, wordnet.NOUN)
              for (word, pos_tag) in pos_tagged_text
          ]
      
          return pos_tagged_text
      

      【讨论】:

        【解决方案7】:

        你可以在一行中做到这一点:

        wnpos = lambda e: ('a' if e[0].lower() == 'j' else e[0].lower()) if e[0].lower() in ['n', 'r', 'v'] else 'n'
        

        然后使用wnpos(nltk_pos) 获取 POS 给 .lemmatize()。在你的情况下,lmtzr.lemmatize(word=tagged[0][0], pos=wnpos(tagged[0][1]))。

        【讨论】:

          【解决方案8】:

          在网上搜索后,我找到了这个解决方案:从句子到“词袋”经过拆分、pos_tagging、词形还原和清理(从标点符号和“停止词”)操作得出。 这是我的代码:

          from nltk.corpus import wordnet as wn
          from nltk.wsd import lesk
          from nltk.stem import WordNetLemmatizer 
          from nltk.corpus import stopwords 
          from nltk.tokenize import word_tokenize
          
          punctuation = u",.?!()-_\"\'\\\n\r\t;:+*<>@#§^$%&|/"
          stop_words_eng = set(stopwords.words('english'))
          lemmatizer = WordNetLemmatizer()
          tag_dict = {"J": wn.ADJ,
                      "N": wn.NOUN,
                      "V": wn.VERB,
                      "R": wn.ADV}
          
          def extract_wnpostag_from_postag(tag):
              #take the first letter of the tag
              #the second parameter is an "optional" in case of missing key in the dictionary 
              return tag_dict.get(tag[0].upper(), None)
          
          def lemmatize_tupla_word_postag(tupla):
              """
              giving a tupla of the form (wordString, posTagString) like ('guitar', 'NN'), return the lemmatized word
              """
              tag = extract_wnpostag_from_postag(tupla[1])    
              return lemmatizer.lemmatize(tupla[0], tag) if tag is not None else tupla[0]
          
          def bag_of_words(sentence, stop_words=None):
              if stop_words is None:
                  stop_words = stop_words_eng
              original_words = word_tokenize(sentence)
              tagged_words = nltk.pos_tag(original_words) #returns a list of tuples: (word, tagString) like ('And', 'CC')
              original_words = None
              lemmatized_words = [ lemmatize_tupla_word_postag(ow) for ow in tagged_words ]
              tagged_words = None
              cleaned_words = [ w for w in lemmatized_words if (w not in punctuation) and (w not in stop_words) ]
              lemmatized_words = None
              return cleaned_words
          
          sentence = "Two electric guitar rocks players, and also a better bass player, are standing off to two sides reading corpora while walking"
          print(sentence, "\n\n bag of words:\n", bag_of_words(sentence) )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-05
            • 2014-05-24
            相关资源
            最近更新 更多