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

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

 I don’t always train machine learning models… …but when I do, 80% of my time is spent cleaning data.
I don’t always train machine learning models… …but when I do, 80% of my time is spent cleaning data.

Что включает предобработка?

Очистка текста от лишних символов

  1. Нормализация регистра (text = text.lower())

  2. Токенизация (разделение на слова)

  3. Лемматизация / стемминг

  4. Удаление стоп-слов

  5. Опционально: 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-файлы — для дальнейшей текстовой работы.

Комментарии (0)