NLTK WordNet Lemmatizer: не следует ли лемммировать все перегибы слова?

Я использую Лемматизатор NLTK WordNet для проекта тегов с частичной речью, сначала изменяя каждое слово в корпусе тренировки на его основу (на месте модификации), а затем тренируясь только на новом корпусе. Тем не менее, я обнаружил, что lemmatizer не работает, как я ожидал.

Например, слово loves лемматизировано на love, что верно, но слово loving остается loving даже после лемматизации. Здесь loving является таким же, как в предложении "Я люблю его".

Является ли love основой отклоненного слова loving? Точно так же многие другие "формы" остаются такими же, как и после лемматизации. Это правильное поведение?

Каковы некоторые другие лемматизаторы, которые точны? (не нужно быть в NLTK) Существуют ли морфологические анализаторы или лемматизаторы, которые также учитывают слово "Часть речи" при решении слова "ствол"? Например, слово killing должно быть kill в качестве основы, если killing используется в качестве глагола, но оно должно иметь killing в качестве основы, если оно используется как существительное (как в the killing was done by xyz),.

Ответ 1

Лемматизатор WordNet учитывает тег POS, но он не волшебным образом определяет его:

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

Без тега POS он предполагает все, что вы кормите, это существительное. Итак, здесь он думает, что вы передаете ему существительное "любящее" (как в "сладкой любви" ).

Ответ 2

Лучший способ устранить эту проблему - фактически посмотреть в Wordnet. Посмотрите здесь: Любить в wordnet. Как вы можете видеть, на самом деле в Wordnet присутствует прилагательное "любящее". На самом деле даже наречие "с любовью": любовно в 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

Надеюсь, что это поможет.

Ответ 3

он более ясный и более эффективный, чем перечисление:

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)

Ответ 4

Аналогичные @bogs

Я использую dict:

from textblob.wordnet import NOUN, VERB, ADJ, ADV

pos_to_wornet_dict = {

    'JJ': ADJ,
    'JJR': ADJ,
    'JJS': ADJ,
    'RB': ADV,
    'RBR': ADV,
    'RBS': ADV,
    'NN': NOUN,
    'NNP': NOUN,
    'NNS': NOUN,
    'NNPS': NOUN,
    'VB': VERB,
    'VBG': VERB,
    'VBD': VERB,
    'VBN': VERB,
    'VBP': VERB,
    'VBZ': VERB,

}

Ответ 5

В качестве дополнения к принятому ответу из @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 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))