NLTK WordNet 词形还原器:难道不应该对一个单词的所有屈折形式进行还原吗?

41 投票
4 回答
61383 浏览
提问于 2025-04-18 18:45

我正在做一个词性标注的项目,使用的是NLTK的WordNet词形还原工具。我的做法是先把训练数据里的每个单词都改成它的词根,然后再用这个新数据进行训练。不过,我发现这个词形还原工具的表现并没有我预期的那么好。

举个例子,单词loves被还原成love,这是对的,但单词loving在还原后却还是loving。这里的loving是指“我喜欢它”这句话里的用法。

难道love不是loving这个变化形式的词根吗?类似的,很多其他以‘ing’结尾的单词在还原后也保持不变。这是正常现象吗?

有没有其他更准确的词形还原工具?(不一定要在NLTK里)有没有那种在决定单词词根时也考虑单词词性标签的词形分析器或词形还原工具?比如,单词killing如果作为动词使用,应该还原成kill,但如果作为名词使用(比如“这次杀戮是xyz干的”),那么它的词根应该还是killing

4 个回答

3

这是对上面@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))
6

这比列举的方式更清晰、更有效:

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)
33

解决这个问题的最好办法是去查查Wordnet。你可以看看这里:Wordnet中的“loving”。如你所见,Wordnet里确实有一个形容词“loving”。实际上,还有一个副词“lovingly”:Wordnet中的“lovingly”。因为Wordnet并不知道你具体想要哪个词性,所以默认给你的是名词(在Wordnet中用'n'表示)。如果你使用的是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

希望这能帮到你。

78

WordNet的词形还原器确实会考虑词性标签,但它并不是凭空判断的:

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

如果没有词性标签,它会默认你输入的所有词都是名词。所以在这个例子中,它认为你传入的是名词“loving”(比如在“甜蜜的爱”中)。

撰写回答