Простой NLP в Python с TextBlob: лемматизация
TextBlob - это пакет, построенный поверх двух других пакетов, один из которых называется Natural Language Toolkit, известный в основном в сокращенной форме как NLTK, а другой - Pattern. NLTK - это традиционный пакет, используемый для обработки текста или естественного языка (NLP), а Pattern создан в основном для веб-майнинга.
TextBlob разработан таким образом, чтобы его было проще изучать и манипулировать им, чем NLTK, сохраняя при этом те же важные задачи NLP, такие как лемматизация, анализ настроений, стемминг, POS-тегирование, извлечение именных фраз, классификация, перевод и многое другое. Вы можете ознакомиться с полным списком задач на странице TextBlob в PyPI.
Если вы ищете практический обзор многих задач NLP, которые могут быть выполнены с помощью TextBlob, ознакомьтесь с нашим руководством "Python для NLP: введение в библиотеку TextBlob".
Для использования TextBlob не требуется никаких специальных технических предпосылок. Например, пакет применим как для Python 2, так и для 3 (Python >= 2.7 или >= 3.5).
Кроме того, на случай, если у вас под рукой нет никакой текстовой информации, TextBlob предоставляет необходимые коллекции языковых данных (обычно текстов), называемые корпусами, из базы данных NLTK.
Установка TextBlob
Начнем с установки TextBlob. Если вы используете терминал, командную строку или командную строку, вы можете ввести:
$ pip install textblob
В противном случае, если вы используете блокнот Jupyter, вы можете выполнить команду прямо из блокнота, добавив восклицательный знак !
в начале инструкции:
!pip install textblob
Примечание. Этот процесс может занять некоторое время из-за большого количества алгоритмов и корпусов, содержащихся в этой библиотеке.
После установки TextBlob, чтобы иметь текстовые примеры, вы можете скачать корпуса, выполнив команду python -m textblob.download_corpora
. Опять же, вы можете выполнить его прямо в командной строке или в блокноте, поставив перед ним восклицательный знак.
При выполнении команды вы должны увидеть вывод ниже:
$ python -m textblob.download_corpora
[nltk_data] Downloading package brown to /Users/csamp/nltk_data...
[nltk_data] Package brown is already up-to-date!
[nltk_data] Downloading package punkt to /Users/csamp/nltk_data...
[nltk_data] Package punkt is already up-to-date!
[nltk_data] Downloading package wordnet to /Users/csamp/nltk_data...
[nltk_data] Package wordnet is already up-to-date!
[nltk_data] Downloading package averaged_perceptron_tagger to
[nltk_data] /Users/csamp/nltk_data...
[nltk_data] Package averaged_perceptron_tagger is already up-to-
[nltk_data] date!
[nltk_data] Downloading package conll2000 to /Users/csamp/nltk_data...
[nltk_data] Unzipping corpora/conll2000.zip.
[nltk_data] Downloading package movie_reviews to
[nltk_data] /Users/csamp/nltk_data...
[nltk_data] Unzipping corpora/movie_reviews.zip.
Finished.
Мы уже установили пакет TextBlob и его корпуса. Теперь давайте больше разберемся в лемматизации.
Для получения дополнительной информации о TextBlob ознакомьтесь с нашими руководствами Simple NLP in Python with TextBlob: Tokenization, Simple NLP in Python with TextBlob: N-Grams Detection и Анализ настроений в Python с TextBlob.
Что такое лемматизация?
Прежде чем углубиться в область NLP, вы должны уметь распознавать некоторые ключевые термины:
Corpus (или корпуса во множественном числе) — это определенный набор языковых данных (например, текстов). Корпуса обычно используются, например, для обучения различных моделей классификации текста или анализа настроений.
Lemma - это слово, которое вы бы искали в словаре. Например, если вы хотите посмотреть определение глагола «бежать», вы должны искать «бежать».
Stem (основа) - это часть слова, которая никогда не изменяется.
Что такое лемматизация?
Лемматизация — это процесс получения лемм слов из корпуса.
Иллюстрацией этого может быть следующее предложение:
- Input (corpus): Алиса думает, что заблудилась, но затем начинает находить себя.
- Output (lemmas): | Алиса | думать | она | есть | потерял | но | затем | начать | к | найти | сама |
Обратите внимание, что каждое слово во входном предложении лемматизировано в соответствии с его контекстом в исходном предложении. Например, "Алиса" - это имя собственное, поэтому оно остается неизменным, а глаголы "думает" и "начинает" упоминаются в их базовых формах "думать" и "начинать".
Лемматизация - один из основных этапов обработки языка. Это приводит слова к их корневым формам или леммам, которые мы нашли бы, если бы искали их в словаре.
В случае TextBlob лемматизация основана на базе данных WordNet, разработанной и поддерживаемой Принстонским университетом. В фоновом режиме TextBlob использует процессор преобразования WordNet для получения леммы для слова.
Примечание. Дополнительные сведения о том, как работает лемматизация в TextBlob, см. в документации.
Вы, вероятно, не заметите существенных изменений при лемматизации, если только не работаете с большими объемами текста. В этом случае лемматизация помогает уменьшить размер слов, которые мы, возможно, ищем, пытаясь сохранить их контекст в предложении. Это может быть применено в дальнейшем при разработке моделей машинного перевода, поисковой оптимизации или различных бизнес-запросов.
Реализация лемматизации в коде
Прежде всего, необходимо установить объект TextBlob и определить образец корпуса, который будет лемматизирован позже. На этом начальном этапе вы можете либо написать, либо определить строку текста для использования, или мы можем использовать пример из загруженного нами корпуса NLTK. Пойдем с последним.
Выбор обзора из корпуса NLTK
Например, попробуем получить леммы для рецензии на фильм, которая есть в корпусе. Для этого мы импортируем как библиотеку TextBlob, так и movie_reviews
из пакета nltk.corpus
:
# importing necessary libraries
from textblob import TextBlob
from nltk.corpus import movie_reviews
После импорта мы можем просмотреть файлы обзоров фильмов с помощью метода fileids().
Поскольку этот код работает в блокноте Jupyter, мы можем выполнить его напрямую:
movie_reviews.fileids()
Это вернет список из 2000 имен текстовых файлов, содержащих отрицательные и положительные отзывы:
['neg/cv000_29416.txt',
'neg/cv001_19502.txt',
'neg/cv002_17424.txt',
'neg/cv003_12683.txt',
'neg/cv004_12641.txt',
'neg/cv005_29357.txt',
'neg/cv006_17022.txt',
'neg/cv007_4992.txt',
'neg/cv008_29326.txt',
'neg/cv009_29417.txt',
...]
Примечание. Если вы запускаете код другим способом, например, в терминале или в среде IDE, вы можете распечатать ответ, выполнив команду print(movie_reviews.fileids())
.
Глядя на neg
в названии файла, можно предположить, что список начинается с отрицательных отзывов и заканчивается положительными. Мы можем посмотреть на положительный отзыв, проведя индексацию с конца списка. Здесь мы выбираем 1989-й отзыв:
movie_reviews.fileids()[-10]
Это приводит к:
'pos/cv990_11591.txt'
Чтобы изучить предложения обзора, мы можем передать имя обзора методу .sents()
, который выводит список всех предложений обзора:
movie_reviews.sents('pos/cv990_11591.txt')
[['the', 'relaxed', 'dude', 'rides', 'a', 'roller', 'coaster',
'the', 'big', 'lebowski', 'a', 'film', 'review', 'by', 'michael',
'redman', 'copyright', '1998', 'by', 'michael', 'redman', 'the',
'most', 'surreal', 'situations', 'are', 'ordinary', 'everyday',
'life', 'as', 'viewed', 'by', 'an', 'outsider', '.'], ['when',
'those', 'observers', 'are', 'joel', 'and', 'ethan', 'coen', ',',
'the', 'surreal', 'becomes', 'bizarre', '.'], ...]
Давайте сохраним этот список в переменной pos_review
:
pos_review = movie_reviews.sents("pos/cv990_11591.txt")
len(pos_review) #returns 63
Здесь мы видим, что есть 63 предложения. Теперь мы можем выбрать одно предложение для лемматизации, например, 15-е предложение:
sentence = pos_review[16]
type(sentence) # returns list
Создание объекта TextBlob
После выбора предложения нам нужно создать объект TextBlob, чтобы иметь доступ к методу .lemmatize()
. Объекты TextBlob необходимо создавать из строк. Поскольку у нас есть список, мы можем преобразовать его в строку с помощью метода string.join()
, объединяя на основе пробелов:
sentence_string = ' '.join(sentence)
Теперь, когда у нас есть строка предложения, мы можем передать ее конструктору TextBlob:
blob_object = TextBlob(sentence_string)
Получив объект TextBlob, мы можем выполнять различные операции, например лемматизацию.
Лемматизация предложения
Наконец, чтобы получить лемматизированные слова, мы просто извлекаем атрибут words
созданного объекта blob_object
. Это дает нам список, содержащий объекты Word, которые ведут себя очень похоже на строковые объекты:
# Word tokenization of the sentence corpus
corpus_words = blob_object.words
# To see all tokens
print('sentence:', corpus_words)
# To count the number of tokens
number_of_tokens = len(corpus_words)
print('\nnumber of tokens:', number_of_tokens)
Выходные команды должны дать вам следующее:
sentence: ['the', 'carpet', 'is', 'important', 'to', 'him', 'because', 'it', 'pulls', 'the', 'room', 'together', 'not', 'surprisingly', 'since', 'it', 's', 'virtually', 'the', 'only', 'object', 'there']
number of tokens: 22
Чтобы лемматизировать слова, мы можем просто использовать метод .lemmatize()
:
corpus_words.lemmatize()
Это дает нам лемматизированный объект WordList:
WordList(['the', 'carpet', 'is', 'important', 'to', 'him', 'because', 'it', 'pull', 'the',
'room', 'together', 'not', 'surprisingly', 'since', 'it', 's', 'virtually', 'the', 'only',
'object', 'there'])
Так как это может быть немного сложно читать, мы можем сделать цикл и вывести каждое слово до и после лемматизации:
for word in corpus_words:
print(f'{word} | {word.lemmatize()}')
Это приводит к:
the | the
carpet | carpet
is | is
important | important
to | to
him | him
because | because
it | it
pulls | pull
the | the
room | room
together | together
not | not
surprisingly | surprisingly
since | since
it | it
s | s
virtually | virtually
the | the
only | only
object | object
there | there
Обратите внимание, как "pulls" изменилось на "pull"; другие слова, кроме "it's", также были лемматизированы, как и ожидалось. Мы также можем видеть, что "it's" было отделено из-за апострофа. Это указывает на то, что мы можем дополнительно предварительно обработать предложение, чтобы "it's" считалось словом, а не "it" и "s".
Разница между лемматизацией и стеммингом
Лемматизацию часто путают с другим методом, называемым стеммингом. Эта путаница возникает из-за того, что оба метода обычно используются для сокращения слов. В то время как лемматизация использует словари и фокусируется на контексте слов в предложении, пытаясь сохранить его, стемминг использует правила для удаления аффиксов слов, фокусируясь на получении основы слова.
Давайте быстро изменим наш цикл for
, чтобы увидеть эти различия:
print('word | lemma | stem\n')
for word in corpus_words:
print(f'{word} | {word.lemmatize()} | {word.stem()}')
Это выводит:
the | the | the
carpet | carpet | carpet
is | is | is
important | important | import
to | to | to
him | him | him
because | because | becaus
it | it | it
pulls | pull | pull
the | the | the
room | room | room
together | together | togeth
not | not | not
surprisingly | surprisingly | surprisingli
since | since | sinc
it | it | it
s | s | s
virtually | virtually | virtual
the | the | the
only | only | onli
object | object | object
there | there | there
Рассматривая приведенный выше результат, мы можем видеть, насколько проблематичным может быть стемминг. Это сокращает "important" до "import", теряя все значение слова, которое теперь даже можно считать глаголом; "because" до "becaus", слова, которого не существует, то же самое для "togeth", "surprisingli", "sinc", "onli".
Существуют четкие различия между лемматизацией и стеммингом. Ключевым моментом является понимание того, когда использовать каждую технику. Предположим, вы оптимизируете поиск слов, и основное внимание уделяется возможности предложить максимальное количество похожих слов, какой метод вы бы использовали? Когда контекст слова не имеет значения, и мы можем получить "important" с помощью "import", очевидный выбор — корень. С другой стороны, если вы работаете над сравнением текста документа, в котором положение слов в предложении имеет значение, а контекст "importance" необходимо сохранить и не путать с глаголом "import", лучшим выбором будет лемматизация.
В последнем сценарии предположим, что вы работаете над поиском слов, за которым следует сравнение текста извлеченного документа, что вы будете использовать? И стемминг, и лемматизация.
Мы поняли разницу между стеммингом и лемматизацией; теперь давайте посмотрим, как мы можем лемматизировать весь обзор, а не просто предложение.
Лемматизация обзора
Чтобы лемматизировать весь обзор, нам нужно только изменить .join()
. Вместо того, чтобы соединять слова в предложение, мы будем соединять предложения в обзоре:
# joining each sentence with a new line between them, and a space between each word
corpus_words = '\n'.join(' '.join(sentence) for sentence in pos_review)
После преобразования корпуса в строку мы можем действовать так же, как это было для предложения, чтобы лемматизировать его:
blob_object = TextBlob(pos_rev)
corpus_words = blob_object.words
corpus_words.lemmatize()
Это генерирует объект WordList с лемматизированным полным текстом обзора. Здесь мы опускаем некоторые части с многоточием (...)
, так как обзор большой, но вы сможете увидеть его в цельном виде. Мы можем найти наше предложение в середине:
WordList(['the', 'relaxed', 'dude', 'rides', 'a', 'roller', 'coaster', 'the', 'big',
'lebowski', 'a', 'film', 'review', 'by', 'michael', 'redman', 'copyright', '1998', 'by',
'michael', 'redman', 'the', 'most', 'surreal', 'situations', 'are', 'ordinary', 'everyday',
'life', 'as', 'viewed', 'by', 'an', 'outsider', 'when', 'those', 'observers', 'are', 'joel',
(...)
'the', 'carpet', 'is', 'important', 'to', 'him', 'because', 'it', 'pulls', 'the', 'room',
'together', 'not', 'surprisingly', 'since', 'it', 's', 'virtually', 'the', 'only', 'object',
'there'
(...)
'com', 'is', 'the', 'eaddress', 'for', 'estuff'])
Вывод
После лемматизации предложения и обзора мы видим, что оба сначала извлекают слова из корпуса. Это означает, что лемматизация происходит на уровне слова, что также подразумевает, что она может быть применена к слову, предложению или полному тексту. Это работает для слова или любой коллекции слов.
Это также говорит о том, что это может быть медленнее, поскольку необходимо сначала разбить текст на токены, чтобы позже применить его. И поскольку лемматизация, как мы видели, зависит от контекста, также крайне важно провести хорошую предварительную обработку текста перед его использованием, обеспечив правильную разбивку на лексемы и соответствующую пометку части речи. И то, и другое улучшит результаты.
Если вы не знакомы с маркировкой частей речи (POS-тегированием), ознакомьтесь с нашим руководством Python для NLP: тегирование частей речи и распознавание именованных объектов.
Мы также видели, чем лемматизация отличается от стемминга — еще одного метода сокращения слов, который не сохраняет их контекст. По этой причине он обычно быстрее.
Есть много способов выполнить лемматизацию, и TextBlob — отличная библиотека для начала работы с NLP. Он предлагает простой API, который позволяет пользователям быстро начать работу над задачами NLP.