Нормализация текста является предварительным этапом в NLP. Почти каждая библиотека предоставляет различные методы нормализации. В этой статье поговорим о двух библиотеках spaCy и NLTK, о том как в них проводится нормализация и кто из них быстрее в этом деле.
Зачем нужна нормализация текста
В NLP очень важно преобразовать исходный текст в такую форму, которая будет легко проинтепретирована алгоритмами машинного обучения (Machine Learning). Именно для этого и используется нормализация текста. Нормализуя текст на естественном языке, мы стремимся уменьшить некоторую случайность поведения и придти к более стандартному виду.
Мы уже как-то говорили о методах нормализации чисел в Apache Spark тут, для текстов тоже существуют различные методы. В математических терминах, нормализация подразумевает приведение случайного распределения к нормальному, как это показано на рисунке выше. Иными словами, цель нормализации — получение ожидаемого поведения. Справедливо говоря, не существует универсального метода нормализации, который подходил бы в каждой ситуации. В некоторых случаях она вообще не требуется. Тем не менее, преимущества нормализации всё же есть.
Преимущества нормализации
Во-первых, нормализация уменьшает набор допустимых вариаций и обобщает входные данные. Это приводит к увеличению производительности и позволяет избежать множества неправильных ответов. Представьте, поисковик, который учитывает набранные слова с именно тем же падежом, спряжением или грамматической ошибкой; такой поисковик выдавал бы те страницы, которые содержат ровно эти слова.
Во-вторых, нормализация уменьшает общую размерность. В машинном обучении высокая размерность — одна из главных проблем. Уменьшение размерности приводит к уменьшению количества вычислений.
NLP с Python
Код курса
PNLP
Ближайшая дата курса
24 февраля, 2025
Продолжительность
40 ак.часов
Стоимость обучения
90 000 руб.
В-третьих, нормализация очищает исходный текст. Будет обидно, если обучение прервется из-за не найденных заранее ошибок, например, символов не входящих в данную кодировку.
Что требуется нормализовать
Как уже было сказано, нет универсального решения для нормализации, поскольку всё зависит от решаемой задачи. Но есть две вещи, на которых мы сфокусируемся:
- Словарь, так как требуется минимизировать размер словаря в большинстве случаев.
- Структура предложений, так как нужно ответить на вопросы вроде: “Как определяется предложение”, “Заканчивается ли предложение знаком пунктуации”, “Нужно ли удалить знаки пунктуации”, “Может нас интересуют только вопросительные предложения” и т.д.
На практике рассматриваются именно эти две задачи в рамках нормализации. Их можно разбить на более простые подзадачи, например:
- Удаление знаков пунктуации и ненужных пробелов.
- Замена числительных выраженных в словесном виде на числа.
- Приведение к одному виду дат, идентификаторов или других данных, которые потенциально имеют определенный формат.
- Удаление стоп-слов (слов, не несущих ценную информацию).
- Замена или удаление конкретных слов.
- Проверка правописания.
- Приведение к одному виду аббревиатур.
- Лемматизация (приведение к одной морфологической форме) или стемминг (удаление окончаний).
Как будет проверена скорость библиотек spaCy и NLTK
В итоге, мы хотим проверить, как проводить нормализацию текста в spaCy и NLTK, а также какая NLP-библиотека работает быстрее. Для этого воспользуемся News API для получения данных. Предложения текстов будем хранить в переменной sentence
. Также нам пригодится функция для удаления знаков препинания, код на Python:
def remove_punctuations(normalized_tokens): punctuations=['?',':','!',',','.',';','|','(',')','--'] for word in normalized_tokens: if word in punctuations: normalized_tokens.remove(word) return normalized_tokens
Нормализация текста в spaCy
В spaCy есть метод nlp
, который инкапсулирует конвейер по обработке текста. Этот конвейер включает токенизацию, определение частей речи (pos-tagging), лемматизацию, парсинг, извлечение сущностей (Named-entity recognition) и т.д. Стоит помнить, что spaCy не имеет инструмента для стемминга, поскольку в нём отдаётся предпочтение лемматизации.
Для токенизации используем класс Tokenizer
:
from spacy.tokenizer import Tokenizer from spacy.lang.en import English vocab = English() tokenizer = vocab.tokenizer tokens = tokenizer(sentence) print(list(tokens)) """[Following, the, debut, of, Bitcoin, futures, ETF, in, the, United, States, ,, the, crypto, market, is, abuzz, with, talks, of, an, impending, Ether, ETF.Speaking, on, a, show, on, CNBC, ,, Michael, Sonnenshein, ,, CEO, of, Grayscale, --, an, asset, management, company, with, $, 52, billion, in, assets, under, management, --, says, it, is, possible, ., He, said, it, ', stands, to, reason, ', the, Securities, and, Exchange, Committee, (, SEC, ), will, proactively, consider, bringing, Ethereum, ETF, and, other, similar, products, in, the, US, market, ., Canada, already, has, Bitcoin, ,, Ethereum, ETFsWhile, US, regulators, have, allowed, Bitcoin, futures, ETF, to, be, traded, on, the, exchanges, ,, Canada, has, allowed, both, Bitcoin, and, Ethereum, ETFs, .]"""
Поскольку мы протестируем скорость работы библиотек, отключим некоторые из частей конвейера. Точнее отключим всё кроме лемматизации и определения частей речи. Второй нужен для лемматизации. Всё, что нужно это передать текст в конвейер и извлечь полученные токены.
nlp = spacy.load('en_core_web_sm', disable=['parser', 'ner', 'tok2vec', 'attribute_ruler']) doc = nlp(sentence)
Произведем лемматизацию:
lemma_list = [] for token in doc: lemma_list.append(token.lemma_) print("Lemmatized tokens:\n") print(lemma_list)
После лемматизации spaCy заменяет все местоимения на -PRON-
. Наконец, избавимся от стоп-слов и используем нашу функцию удаления знаков пунктуации и проведем нормализацию текста:
normalized_tokens = [] for word in lemma_list: lexeme = nlp.vocab[word] if lexeme.is_stop == False: normalized_tokens.append(word) normalized_tokens = remove_punctuations(normalized_tokens) print("\nText after removing stopwords & punctuations:\n") print(normalized_tokens) """Text after removing stopwords & punctuations: ['follow', 'debut', 'Bitcoin', 'future', 'etf', 'United', 'States', 'crypto', 'market', 'abuzz', 'talk', 'impend', 'Ether', 'etf.speake', 'CNBC', 'Michael', 'Sonnenshein', 'ceo', 'Grayscale', 'asset', 'management', 'company', '$', '52', 'billion', 'asset', 'management', '-PRON-', 'possible', '-PRON-', '-PRON-', "'", 'stand', 'reason', "'", 'Securities', 'Exchange', 'Committee', 'SEC', 'proactively', 'consider', 'bring', 'Ethereum', 'etf', 'similar', 'product', 'market', 'Canada', 'Bitcoin', 'Ethereum', 'ETFsWhile', 'regulator', 'allow', 'Bitcoin', 'future', 'etf', 'trade', 'exchange', 'Canada', 'allow', 'Bitcoin', 'Ethereum', 'etf'] """
Нормализация текста в NLTK
В отличие от spaCy, в NLTK есть поддержка стемминга. Причём имеется два варианта: Porter и Snowball. Мы используем первый вариант. Но перед этим необходимо скачать токенизатор, лемматизатор и список стоп-слов.
import nltk nltk.download('punkt') nltk.download('wordnet') nltk.download('stopwords')
Теперь можно приступать к стеммингу и лематизации:
from nltk.tokenize import word_tokenize from nltk.corpus import stopwords from nltk.stem import WordNetLemmatizer from nltk.stem.porter import * stemmer = PorterStemmer() tokens = word_tokenize(sentence) #Stemming stemed_tokens = [] for word in tokens: stemed_tokens.append(stemmer.stem(word)) #Lemmatization lemmatizer = WordNetLemmatizer() nltk_lemma_list = [] for word in stemed_tokens: nltk_lemma_list.append(lemmatizer.lemmatize(word))
Имея список стоп-слов и функцию удаления пунктуации, проведём нормализацию предложений. Код на Python:
normalized_tokens = [] nltk_stop_words = set(stopwords.words("english")) for w in nltk_lemma_list: if w not in nltk_stop_words: normalized_tokens.append(w) #Removing the punctuations normalized_tokens = remove_punctuations(normalized_tokens) print(" ") print("\nText after removing stopwords & punctuations:\n") print(normalized_tokens) """ Text after removing stopwords & punctuations: ['follow', 'debut', 'bitcoin', 'futur', 'etf', 'unit', 'state', 'crypto', 'market', 'abuzz', 'talk', 'impend', 'ether', 'etf.speak', 'show', 'cnbc', 'michael', 'sonnenshein', 'ceo', 'grayscal', 'asset', 'manag', 'compani', '$', '52', 'billion', 'asset', 'manag', 'say', 'possibl', 'He', 'said', "'stand", 'reason', "'", 'secur', 'exchang', 'committe', 'sec', 'proactiv', 'consid', 'bring', 'ethereum', 'etf', ' similar', 'product', 'US', 'market.canada', 'alreadi', 'ha', 'bitcoin', 'ethereum', 'etfswhil', 'US', 'regul', 'allow', 'bitcoin', 'futur', 'etf', 'trade', 'exchang', 'canada', 'ha', 'allow', 'bitcoin', 'ethereum', 'etf'] """
Кто же быстрее: spaCy или NLTK
Для проверки скорости работы двух библиотек воспользуемся магической командой %%time
(о магических командах в Jupyter мы говорили тут). Объединим 100 статей в один корпус и сравним скорость выполнения.
sentence = " ".join(summary) %%time spacy_pipeline(sentence) Total normalized tokens: 7177 CPU times: user 415 ms, sys: 6.81 ms, total: 422 ms Wall time: 422 ms %%time nltk_pipeline(sentence) Total normalized tokens:7505 CPU times: user 448 ms, sys: 3.48 ms, total: 451 ms Wall time: 452 ms
На небольшом корпусе разница несущественная. Но благодаря более робастному процессу лемматизации spaCy способен уменьшать корпус до токенов меньшего размера. Мы рекомендуем всё же использовать spaCy, поскольку конвейер подвергается различным оптимизациям, что делает его гораздо быстрее, чем NLTK.
Ещё больше подробностей о нормализации текста с реальными примерами из Data Science вы узнаете на специализированном курсе по машинному обучению «PNLP: NLP — обработка естественного языка с Python» в лицензированном учебном центре обучения и повышения квалификации разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве.