NLTK WordNet Lemmatizer:它不应该把一个词的所有变形都搞定吗?

时间:2014-08-27 18:10:12

标签: python nlp nltk

我正在使用NLTK WordNet Lemmatizer进行词性标注项目,首先将训练语料库中的每个单词修改为其词干(就地修改),然后仅对新语料库进行训练。但是,我发现lemmatizer没有按照我的预期运行。

例如,单词loves被词形化为love,这是正确的,但即使在词形还原后,单词loving仍然是loving。这里loving与句子“我喜欢它”一样。

love不是词loving的词干吗?同样,许多其他“ing”形式仍然存在于词形还原之后。这是正确的行为吗?

哪些其他引理器准确无误? (不需要在NLTK中)是否有形态分析器或词形变换器在决定单词词干时还考虑了单词的词性标记?例如,如果将killing用作动词,则kill一词应为killing,但如果将killing用作词干,则应将the killing was done by xyz作为词干。名词(如{{1}})。

4 个答案:

答案 0 :(得分:56)

WordNet引理器确实考虑了POS标签,但它没有神奇地决定它:

>>> nltk.stem.WordNetLemmatizer().lemmatize('loving')
'loving'
>>> nltk.stem.WordNetLemmatizer().lemmatize('loving', 'v')
u'love'

如果没有POS标签,它会假定您提供的所有内容都是名词。所以在这里它认为你传给它名词“爱”(如“甜蜜的爱”)。

答案 1 :(得分:27)

解决此问题的最佳方法是实际查看Wordnet。看看这里:Loving in wordnet。正如你所看到的,实际上有一个形容词" loving"存在于Wordnet中。事实上,甚至有一个副词"爱心":lovingly in Wordnet。因为wordnet实际上并不知道你真正想要的是什么词性,所以它默认为名词(' n'在Wordnet中)。如果您使用的是Penn Treebank标记集,这里有一些方便的功能可以将Penn转换为WN标记:

from nltk.corpus import wordnet as wn

def is_noun(tag):
    return tag in ['NN', 'NNS', 'NNP', 'NNPS']


def is_verb(tag):
    return tag in ['VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ']


def is_adverb(tag):
    return tag in ['RB', 'RBR', 'RBS']


def is_adjective(tag):
    return tag in ['JJ', 'JJR', 'JJS']


def penn_to_wn(tag):
    if is_adjective(tag):
        return wn.ADJ
    elif is_noun(tag):
        return wn.NOUN
    elif is_adverb(tag):
        return wn.ADV
    elif is_verb(tag):
        return wn.VERB
    return None

希望这有帮助。

答案 2 :(得分:2)

它比枚举更清晰,更有效:

from nltk.corpus import wordnet

def get_wordnet_pos(self, 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 ''

def penn_to_wn(tag):
    return get_wordnet_pos(tag)

答案 3 :(得分:0)

作为上面@Fred Foo接受的答案的扩展;

from nltk import WordNetLemmatizer, pos_tag, word_tokenize

lem = WordNetLemmatizer()
word = input("Enter word:\t")

# Get the single character pos constant from pos_tag like this:
pos_label = (pos_tag(word_tokenize(word))[0][1][0]).lower()

# pos_refs = {'n': ['NN', 'NNS', 'NNP', 'NNPS'],
#            'v': ['VB', 'VBD', 'VBG', 'VBN', 'VBP', 'VBZ'],
#            'r': ['RB', 'RBR', 'RBS'],
#            'a': ['JJ', 'JJR', 'JJS']}

if pos_label == 'j': pos_label = 'a'    # 'j' <--> 'a' reassignment

if pos_label in ['r']:  # For adverbs it's a bit different
    print(wordnet.synset(word+'.r.1').lemmas()[0].pertainyms()[0].name())
elif pos_label in ['a', 's', 'v']: # For adjectives and verbs
    print(lem.lemmatize(word, pos=pos_label))
else:   # For nouns and everything else as it is the default kwarg
    print(lem.lemmatize(word))