Лемматизация слов после тегирования POS дает неожиданные результаты

Я использую python3.5 с функцией nltk pos_tag и WordNetLemmatizer. Моя цель - сгладить слова в нашей базе данных для классификации текста. Я пытаюсь протестировать с помощью лемматизатора и сталкиваюсь со странным поведением при использовании тега POS для идентичных токенов. В приведенном ниже примере у меня есть список из трех строк, и при их запуске в теге POS каждый другой элемент возвращается как существительное (NN), а остальные возвращаются как глаголы (VBG).

Это влияет на лемматизацию. Выход выглядит так:

pos Of token: v
lemmatized token: skydive
pos Of token: n
lemmatized token: skydiving
pos Of token: v
lemmatized token: skydive

Если я добавлю больше элементов в список идентичных строк, этот же шаблон продолжится. Полный код, который я использую, таков:

tokens = ['skydiving', 'skydiving', 'skydiving']
lmtzr=WordNetLemmatizer()

def get_wordnet_pos(treebank_tag):
    if treebank_tag.startswith('J'):
        return 'a'
    elif treebank_tag.startswith('V'):
        return 'v'
    elif treebank_tag.startswith('N'):
        return 'n'
    elif treebank_tag.startswith('R'):
        return 'r'
    elif treebank_tag.startswith('S'):
        return ''
    else:
        return ''

numTokens = (len(tokens))
for i in range(0,numTokens):
    tokens[i]=tokens[i].replace(" ","")

noSpaceTokens = pos_tag(tokens)

for token in noSpaceTokens:
    tokenStr = str(token[1])
    noWhiteSpace = token[0].replace(" ", "")
    preLemmed = get_wordnet_pos(tokenStr)
    print("pos Of token: " + preLemmed)
    lemmed = lmtzr.lemmatize(noWhiteSpace,preLemmed)
    print("lemmatized token: " + lemmed)

person kinghenry14    schedule 15.10.2015    source источник


Ответы (1)


Короче:

При тегировании POS вам нужно контекстное предложение, а не список неграмматических токенов.

При лемматизации предложения вне контекста единственный способ получить правильную лемму - это вручную указать теги pos.


В долгом:

Тегер POS обычно работает с полным предложением, а не с отдельными словами. Когда вы пытаетесь пометить одно слово вне контекста, вы получаете наиболее частый тег.

Чтобы убедиться, что при пометке одного слова (т. Е. Предложения, состоящего только из 1 слова) он всегда дает один и тот же тег:

>>> from nltk.stem import WordNetLemmatizer
>>> from nltk import pos_tag
>>> ptb2wn_pos = {'J':'a', 'V':'v', 'N':'n', 'R':'r'}
>>> sent = ['skydive']
>>> most_frequent_tag = pos_tag(sent)[0][1]
>>> most_frequent_tag
'JJ'
>>> most_frequent_tag = ptb2wn_pos[most_frequent_tag[0]]
>>> most_frequent_tag
'a'
>>> for _ in range(1000): assert ptb2wn_pos[pos_tag(sent)[0][1][0]] == most_frequent_tag;
... 
>>>

Теперь, поскольку по умолчанию тег всегда равен 'a', если в предложении есть только 1 слово, тогда WordNetLemmatizer всегда будет возвращать skydive:

>>> wnl = WordNetLemmatizer()
>>> wnl.lemmatize(sent[0], pos=most_frequent_tag)
'skydive'

Давайте посмотрим на лемму слова в контексте предложения:

>>> sent2 = 'They skydrive from the tower yesterday'
>>> pos_tag(sent2.split())
[('They', 'PRP'), ('skydrive', 'VBP'), ('from', 'IN'), ('the', 'DT'), ('tower', 'NN'), ('yesterday', 'NN')]
>>> pos_tag(sent2.split())[1]
('skydrive', 'VBP')
>>> pos_tag(sent2.split())[1][1]
'VBP'
>>> ptb2wn_pos[pos_tag(sent2.split())[1][1][0]]
'v'

Таким образом, контекст входного списка токенов имеет значение, когда вы делаете pos_tag.

В вашем примере у вас был список ['skydiving', 'skydiving', 'skydiving'], означающий, что предложение, которое вы помечаете, является неграмматическим предложением:

прыжки с парашютом прыжки с парашютом прыжки с парашютом

И функция pos_tag считает нормальным предложением, поэтому дает теги:

>>> sent3 = 'skydiving skydiving skydiving'.split()
>>> pos_tag(sent3)
[('skydiving', 'VBG'), ('skydiving', 'NN'), ('skydiving', 'VBG')]

В этом случае первое слово - это глагол, второе слово - существительное, а третье слово - глагол, что вернет следующую лемму (которую вы не желаете):

>>> wnl.lemmatize('skydiving', 'v')
'skydive'
>>> wnl.lemmatize('skydiving', 'n')
'skydiving'
>>> wnl.lemmatize('skydiving', 'v')
'skydive'

Поэтому, если у нас есть допустимое грамматическое предложение в вашем списке токенов, результат может выглядеть совсем иначе.

>>> sent3 = 'The skydiving sport is an exercise that promotes diving from the sky , ergo when you are skydiving , you feel like you are descending to earth .'
>>> pos_tag(sent3.split())
[('The', 'DT'), ('skydiving', 'NN'), ('sport', 'NN'), ('is', 'VBZ'), ('an', 'DT'), ('exercise', 'NN'), ('that', 'IN'), ('promotes', 'NNS'), ('diving', 'VBG'), ('from', 'IN'), ('the', 'DT'), ('sky', 'NN'), (',', ','), ('ergo', 'RB'), ('when', 'WRB'), ('you', 'PRP'), ('are', 'VBP'), ('skydiving', 'VBG'), (',', ','), ('you', 'PRP'), ('feel', 'VBP'), ('like', 'IN'), ('you', 'PRP'), ('are', 'VBP'), ('descending', 'VBG'), ('to', 'TO'), ('earth', 'JJ'), ('.', '.')]
person alvas    schedule 16.10.2015
comment
Да, я боялся, что проблема была в отсутствии контекста. Думаю, я пытался погрузиться в nltk без должного фона. Начнем книгу с главы 1 сейчас. Придется найти альтернативный способ, чтобы попытаться решить эту проблему. - person kinghenry14; 17.10.2015