как изменить Wordnet Lemmatizer для леммитизации определенных слов?

Я применяю лемматизатор wordNet в своем корпусе, и мне нужно определить тег pos для лемматизатора:

stemmer = PorterStemmer()
def lemmitize(document):
    return stemmer.stem(WordNetLemmatizer().lemmatize(document, pos='v'))

def preprocess(document):
output = []
    for token in gensim.utils.simple_preprocess(document):
        if token not in gensim.parsing.preprocessing.STOPWORDS and len(token) > 3:
            print("lemmitize: ", lemmitize(token))
            output.append(lemmitize(token))
    return output

Теперь, как вы можете видеть, я определяю pos для глагола (и я знаю, что pos по умолчанию в wordNet — это существительное), однако, когда я лемматизировал свой документ:

the left door closed at the night  

Я выхожу как:

output:  ['leav', 'door', 'close', 'night']

что это не то, что я ожидал. В приведенных выше предложениях left указывает на какую дверь (например, на правую или на левую). Если я выберу pos ='n', эта проблема может быть решена, но тогда она будет действовать как изношенная сеть по умолчанию и не будет влиять на такие слова, как taken.

Я нашел аналогичную проблему в здесь и изменил список исключений в nltk_data/corpora/wordnet/verb.exc, и я изменил left leave на left left, но все же я получаю те же результаты, что и leav.
Теперь мне интересно, есть ли какое-либо решение этой проблемы или, в лучшем случае, есть ли способ, которым я можно добавить собственный словарь некоторых слов (только для моего документа), чтобы wordNet не лемматизировал их, например:

my_dict_list = [left, ...]

person Bilgin    schedule 17.08.2019    source источник
comment
Используете ли вы стеммер намеренно? Кроме того, знаете ли вы, что вы можете найти POS на основе контекста, а не жестко запрограммировать его?   -  person Tiago Duque    schedule 22.08.2019
comment
@TiagoDuque Спасибо за ваш комментарий. Я думаю, что лемматизация может нормализовать мой текст, и мне не нужно искать корни, так как мне нужно, чтобы слова были корневым форматом. Не могли бы вы предоставить дополнительную информацию о том, как найти POS в зависимости от контекста? спасибо   -  person Bilgin    schedule 09.09.2019
comment
Конечно, дай мне немного времени.   -  person Tiago Duque    schedule 09.09.2019


Ответы (2)


Вы можете добавить собственный словарь для определенных слов, например pos_dict = {'breakfasted':'v', 'left':'a', 'taken':'v'}.

Передавая этот настроенный pos_dict вместе с token в функцию lemmitize, вы можете использовать лемматизатор для каждого токена с указанным вами тегом POS.

lemmatize(token, pos_dict.get(token, 'n')) передаст 'n' в качестве второго аргумента в качестве значения по умолчанию, если только токен не находится в ключах pos_dict. Вы можете изменить это значение по умолчанию на любое другое.

def lemmitize(document, pos_dict):
    return stemmer.stem(WordNetLemmatizer().lemmatize(document, pos_dict.get(document, 'n')))

def preprocess(document, pos_dict):
    output = []
    for token in gensim.utils.simple_preprocess(document):
        if token not in gensim.parsing.preprocessing.STOPWORDS and len(token) > 3:
            print("lemmitize: ", lemmitize(token, pos_dict))
            output.append(lemmitize(token, pos_dict))
    return output
person Coding4pho    schedule 21.08.2019
comment
Спасибо за комментарий и извините за поздний ответ. В приведенном выше коде не должно работать, так как `` lemmitize(document)`` принимает один позиционный аргумент, но вы передавали два в print("lemmitize: ", lemmitize(token, pos_dict.get(token, 'n'))). Не могли бы вы проверить это? Благодарность - person Bilgin; 10.09.2019
comment
Мои извинения! Возможно, я запутался между вашей функцией lemmitize() и lemmatize() WordNetLemmatizer, пока печатал свой ответ. Теперь это исправлено. - person Coding4pho; 11.09.2019
comment
Спасибо за исправление кода. Теперь он работает нормально. - person Bilgin; 29.09.2019

Вы сделали распространенную ошибку между лемматизацией и стеммингом.

Вывод

Стемминг означает сокращение слова до его префикса. Это не связано с грамматикой, но связано с вашими собственными данными или используемым алгоритмом.

Наиболее часто используемый стеммер, Porter Stemmer, например, удаляет «морфологические и флективные окончания слов» (Porter Stemmer). Веб-сайт)

Таким образом, у таких слов, как готовить, готовить, готовить и печенье, удаляются морфологические / флективные окончания, и все они оканчиваются на «Готовить». Однако обратите внимание, что вы объединяете вместе существительное, глагол в настоящем продолженном времени, глагол в прошедшем времени и еще одно существительное, все вместе (обратите внимание, что печенье, например, хотя и является приготовленной едой, на самом деле не разделяют «иерархию» со словом «готовить» или «готовить»).

Когда вы делаете:

stemmer.stem(WordNetLemmatizer().lemmatize(document))

Вы создаете основу с помощью wordnet. Сначала вы лемматизируете слово, затем создаете его основу, удаляя «морфологические / флективные» слова. На самом деле вам даже не нужно лемматизировать, если вы делаете стемминг (это изменит что-то только с неправильными глаголами).

Лемматизация

Лемматизация, с другой стороны, использует лексическую информацию, чтобы привести слово к его «по умолчанию», не сгибаемой форме. Чтобы это работало, очень важно указать te POS (поскольку, как вы видели, Leaves — это лексема, представляющая как глагол, так и существительное).

Но как найти часть речи?

Сегодня есть несколько методов, но наиболее часто используемый основан на таблице поиска и окружающих словах — они вводятся в предварительно обученный алгоритм машинного обучения, который возвращает наиболее вероятный тег. Подробнее читайте в: https://medium.com/greyatom/learning-pos-tagged-chunking-in-nlp-85f7f811a8cb

Используя популярный пакет Python NLP под названием NLTK, вы можете сделать: (сначала вам нужно загрузить соответствующие пакеты)

import nltk

sentence = "I want to tag these!"
token = nltk.word_tokenize(sentence)
nltk.pos_tag(token)

Результат:

[('Я', 'PRP'), ('хочу', 'VBP'), ('to', 'TO'), ('метка', 'VB'), ('эти', 'DT') , ('!', '.')]

Еще одним популярным инструментом является Spacy, который работает следующим образом: (сначала вам необходимо загрузить языковую модель с моделью, обученной машинным обучением)

import spacy

import spacy
nlp = spacy.load('en')
doc = nlp('I want to tag these!')
print([(token.text, token.pos_) for token in doc])

Результат:

[('Я', 'ПРОН'), ('хочу', 'ГЛАГОЛ'), ('к', 'ЧАСТЬ'), ('метка', 'ГЛАГОЛ'), ('эти', 'DET') , ('!', 'ПУНКТ')]

Подробнее о POS-тегах Spacy можно прочитать здесь: https://spacy.io/usage/linguistic-features/

Затем я бы порекомендовал вам придерживаться лемматизации, так как это даст вам более тонкие варианты работы.

person Tiago Duque    schedule 09.09.2019
comment
@Tiango Duque Спасибо за ваш комментарий и очень хорошее объяснение. Я проверил ссылку, которую вы указали выше, но я ищу ответы, такие как предложенные @@Coding4pho, или любое динамическое решение этой проблемы. - person Bilgin; 10.09.2019