В предыдущей статье мы рассмотрели, как извлечь текст из PDF с помощью easyocr и fitz.
Теперь, когда у нас есть "сырой" текст, пришло время привести его в порядок..
Этап "очистки" называется предобработкой текста (text preprocessing) и напрямую влияет на точность модели, если текст используется для обучения, а также на качество анализа, если текст обрабатывается напрямую.

Что включает предобработка?
Очистка текста от лишних символов
Нормализация регистра (text = text.lower())
Токенизация (разделение на слова)
Лемматизация / стемминг
Удаление стоп-слов
Опционально: POS-теггинг
В проекте EduText Analyzer (автоматизированный анализ учебников по иностранным языкам) мы используем комбинации этапов. Где-то лемматизация, стемминг, токенизация не требуются. Единственное, что, пожалуй, необходимо всегда – очистка текста от “мусора” (пунктуации, цифр, случайных комбинаций, оставшихся после конвертации из PDF).

Очистка текста от лишних символов
Учебники часто содержат:
случайные символы (", ', …, ‑, ‑);
«битые» последовательности (аа, мм, жжж, kdg, eogrfnb);
двойные пробелы;
строчные/заглавные несоответствия.
Разберем пример кода с регулярными выражениями для подготовки данных для обучения модели на базе логистической регрессии по определению типов упражнений по коммуникативной направленности (языковые/коммуникативные).
import re def clean_sentence(text): text = raw.lower() - нижний регистр # удаляем короткие 2–3-буквенные фрагменты на кириллице text = re.sub(r'\b[а-яА-Я]{2,3}\b', '', text) # оставляем только буквы латиницы/кириллицы и пробелы text = re.sub(r'[^а-яА-Яa-zA-Z\s]', ' ', text) # убираем лишние пробелы text = re.sub(r'\s+', ' ', text) return text.strip()
Пример работы:
raw = "РасскаЖи другу1 5о… св оем любимом уроКЕ.!¶" print(clean_sentence(raw)) # вывод: расскажи другу о любимом уроке
Почему регулярки?? re встроен в Python и не требует дополнительных зависимостей, работает быстро и адаптивен к различным паттернам.
Как вариант для очистки лишних символов можно использовать:
clean-text — быстро удаляет HTML, эмодзи, повторяющиеся символы;
ftfy — исправляет «битые» юникод-символы после конверсии PDF.
Нормализация регистра
Нормализация регистра может быть осуществлена с помощью простого встроенного метода строк в Python (text = text.lower()), так что на этом не останавливаемся подробно, идем к токенизации.
text = text.lower() #расскажи другу о любимом уроке
Токенизация
В EduText мы токенизируем тексты школьных учебников, чтобы, например, выделить лексемы для частотного анализа и классификации по CEFR (уровень сложности слов по Европейской шкале);
Для токенизации мы используем библиотеку spaCy, которая содержит готовые языковые модели (для английского: en_core_web_sm, для русского: ru_core_web_sm).
!python -m spacy download ru_core_news_sm import spacy # Загружаем модель spaCy nlp = spacy.load("ru_core_news_sm") # или "en_core_web_sm" для английского # Функция токенизации только слов (чистая лексика) def tokenize_words(text): doc = nlp(str(text)) # Преобразуем текст в объект Doc spaCy # Возвращаем список слов в нижнем регистре, исключая пунктуацию и числа return [token.text.lower() for token in doc if token.is_alpha] # Функция токенизации с сохранением пунктуации def tokenize_with_punct(text): doc = nlp(str(text)) # Преобразуем текст в объект Doc spaCy # Возвращаем список всех токенов кроме пробелов return [token.text for token in doc if not token.is_space] # Пример использования text = "Послушай и найди артиста на картинке: Скажи, Что OH умеет делать" print(tokenize_words(text)) # ['послушай', 'и', 'найди', 'артиста', 'на', 'картинке', 'скажи', 'что', 'он', 'умеет', 'делать'] print(tokenize_with_punct(text)) # ['Послушай', 'и', 'найди', 'артиста', 'на', 'картинке', ':', 'Скажи', ',', 'Что', 'OH', 'умеет', 'делать']
Функция | Что возвращает | Когда использовать |
tokenize_words | Только слова | Для частотного анализа, обучения модели |
tokenize_with_punct | Слова + пунктуацию | Для восстановления предложений, анализа структуры текста |
Также для токенизации можно использовать NLTK (Natural Language Toolkit). И, конечно, Hugging face transformers.
Лемматизация / стемминг
После токенизации и очистки текста важно привести слова к базовой форме (лемме), чтобы можно было объединять разные формы одного слова (runs - run).
Будем также использовать spaCy для лемматизации, пока что сохраняя стоп-слова, чтобы не разрушать фразы.
import spacy # Загружаем модель spaCy nlp = spacy.load("en_core_web_sm") def lemmatize_page(text): doc = nlp(text) # text уже в нижнем регистре tokens = [token.lemma_.strip() for token in doc if token.is_alpha] # только буквы return ' '.join(tokens) page_text = "Nick's big rabbit is grey and black." # пример текста print(lemmatize_page(page_text)) # Вывод: Nick big rabbit be grey and black
Удаление стоп-слов
Стоп-слова — это слова, которые обычно не несут смысловой нагрузки сами по себе, часто являются служебными словами: артикли, предлоги, союзы, местоимения.
Примеры на английском: the, and, is, in, on.
Примеры на русском: и, в, на, что, как.
Иногда стоп-слова оставляем, если важна структура фразы — например, при точном поиске фраз в учебнике. Но для анализа лексики их удаляем.
import re from nltk.corpus import stopwords import nltk # Загружаем стоп-слова nltk.download("stopwords") stop_words = set(stopwords.words("english")) def extract_words(phrase): """ Разбивает фразу на слова, удаляет знаки препинания и стоп-слова. Параметры: phrase (str): Возвращает: list: список значимых слов """ # Убираем пунктуацию и приводим к нижнему регистру phrase = re.sub(r'[^\w\s]', '', phrase).lower() # Разбиваем на слова и удаляем стоп-слова return [word for word in phrase.split() if word not in stop_words] example_phrase = "Nick's big rabbit is grey and black." print(extract_words(example_phrase)) # Вывод: ['nicks', 'big', 'rabbit', 'grey', 'black']
POS (Part-of-Speech Tagging)
POS (Part-of-Speech Tagging) позволяет определить часть речи каждого слова — существительное, глагол, прилагательное и т.д.
Это полезно для анализа структуры предложений, выделения ключевых слов и построения грамматических шаблонов.
import spacy nlp = spacy.load("en_core_web_sm") doc = nlp("Nick's big rabbit is grey and black.") for token in doc: print(token.text, token.pos_)
#Вывод Nick PROPN 's PART big ADJ rabbit NOUN is AUX grey ADJ and CCONJ black ADJ . PUNCT
После предобработки текста данные сохраняются в форматах CSV или TXT для последующего анализа, обработки или обучения:3. CSV-файлы удобны для работы с таблицами и метаданными, обучения, а TXT-файлы — для дальнейшей текстовой работы.
