Аналитика12 октября 2026 г.

Утечка данных при обучении модели: как проверить порядок подготовки выборок

Автор
Ненашев А.
На чтение
8 мин
Дата обновления
12.10.2026
Старт:С 8 сентября
Срок обучения:24 часа
Машинное обучение для анализа естественного языка (NLP)
Научитесь применять машинное обучение для анализа текстов и решения реальных задач NLP. Курс сочетает теорию и практику: от предобработки текстов до работы с BERT и GPT. Освойте современные методы обработки естественного языка (NLP) и научитесь применять их в проектах. Уникальность — акцент на практику с использованием Python и предобученных моделей. Тренинг по обработке естественного языка с помощью машинного обучения предназначен для тех, кто хочет познакомиться со сложными методами обработки текстовых данных. Он включает в себя необходимый минимум теории и большой объем практических занятий, позволяющих участникам овладеть необходимыми навыками для работы в области анализа данных. К каждому модулю предлагаются задания для самостоятельного выполнения - домашние работы. В рамках тренинга участники изучат методы преобразования текстовых данных, такие как стемминг, лемматизация и векторизация, а также базовые задачи, которые могут быть решены с помощью методов машинного обучения, такие как классификация, суммаризация текстов, выделение имен и другие. Будет уделено особое внимание практическому применению методов машинного обучения на языке Python с использованием современных нейросетей, таких как FastText, BERT и GPT-2.
Подробнее
42 000 ₽42 900 ₽
#COURSE##INNER#

Утечка данных при обучении модели: как проверить порядок подготовки выборок

Вопрос здесь узкий и практический: как убедиться, что в текстовой классификации преобразования обучаются только на train, а не подсматривают в test. Ошибка обычно возникает не в модели, а раньше — в момент, когда весь корпус уже отправили в TF-IDF, отбор признаков или другую обучаемую трансформацию, а разделение на выборки сделали позже. На маленьком примере такая схема может выглядеть безобидно, но проверка качества получится слишком оптимистичной: модель получила сведения о будущем тесте еще до оценки.

Для коротких учебных текстов риск особенно заметен, потому что словарь и веса признаков сильно зависят от каждого документа. Если слово встретилось только в отложенном наборе, а векторизатор уже видел его при fit, граница между обучением и проверкой уже нарушена. Ниже разберем, где именно появляется подсматривание, какой порядок действий считать безопасным и как проверить это не на словах, а по состоянию объекта Pipeline.

Откуда появляется подсматривание в текстовой задаче

В текстовой классификации обучаемой частью часто оказывается не только классификатор, но и векторизация. TfidfVectorizer строит словарь и считает статистики корпуса, поэтому он учится на данных. Если сначала вызвать fit_transform на всех текстах, а потом разрезать матрицу на train и test, то тест уже повлиял на признаки: в словарь попали его слова, а веса IDF посчитаны с учетом документов, которые модель якобы не должна была видеть.

Здесь важен неприятный нюанс: утечка возможна даже без явного использования меток классов. Достаточно того, что преобразование опирается на весь набор данных. Документация scikit-learn прямо предупреждает: test нельзя использовать для выбора или обучения преобразований, а общий порядок должен быть таким — сначала разделение, потом fit только на train, затем transform для test. То же относится не только к TF-IDF, но и к масштабированию, заполнению пропусков, PCA и отбору признаков.

Из-за этого проверка качества становится красивее, чем должна быть. Модель оценивают в слишком удобных условиях, а после переноса на новые данные результат проседает. В статье ниже я не буду обещать качество на игрушечном корпусе: на миниатюрных данных нас интересует не точность, а правильная граница обучения преобразований.

Правильный порядок: сначала split, потом fit только на train

Рабочая схема для коротких текстов выглядит так: вы храните сырые строки и метки, делите их на train и test, затем обучаете все шаги, у которых есть fit, только на train. После этого те же самые шаги применяются к test через transform или автоматически внутри Pipeline. Это правило полезно тем, что его легко проверять: любой объект, который умеет чему-то «учиться» на корпусе, не должен получать test на этапе fit.

Есть и более тонкий вопрос: можно ли что-то делать до split? Если операция полностью детерминированная и не оценивает статистики корпуса, например приведение регистра или замена фиксированного символа по заранее заданному правилу, сама по себе она не обучается на данных. Но на практике безопаснее собирать даже такие шаги в один конвейер или как минимум строго отделять их от шагов с fit. Так проще не ошибиться, когда к простому lower() позже добавятся стоп-слова, словарь или отбор признаков.

Pipeline удобен не потому, что магически убирает все утечки, а потому, что дисциплинирует порядок вызовов. В scikit-learn конвейер вызывает fit на промежуточных шагах во время обучения на train и использует только transform при предсказании. Это же особенно полезно в кросс-валидации и подборе параметров: если вы передаете в процедуру уже готовую матрицу, собранную на всем корпусе, проверка может оказаться искаженной еще до старта.

Пайплайн на учебной задаче с короткими текстами

Учебный пример. Ниже условный корпус из коротких учебных текстов по двум темам: математика и литература. Мы специально оставим в test слова, которых не было в train: логарифм и эпиграф. Если векторизатор обучить на всем корпусе, эти слова попадут в словарь. Если обучить только на train, они останутся вне словаря, и это как раз будет корректным поведением.

Среда примера: Python 3 и scikit-learn. Мы не оцениваем качество модели по такому набору, а проверяем порядок подготовки данных. Проверяемый результат здесь простой: размер словаря и наличие тестовых слов в vocabulary_.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline

X_train = [
    'алгебра дроби формула',
    'геометрия угол площадь',
    'уравнение корень график',
    'дробь степень алгебра',
    'роман сюжет герой',
    'стих рифма поэт',
    'повесть герой глава',
    'лирика образ рифма'
]

y_train = ['math', 'math', 'math', 'math', 'lit', 'lit', 'lit', 'lit']

X_test = [
    'логарифм функция производная',
    'сонет метафора эпиграф'
]

y_test = ['math', 'lit']

# Неправильно: векторизация обучается на всем корпусе
all_texts = X_train + X_test
bad_vectorizer = TfidfVectorizer()
X_all = bad_vectorizer.fit_transform(all_texts)

print(len(bad_vectorizer.vocabulary_))         # 27
print('логарифм' in bad_vectorizer.vocabulary_) # True
print('эпиграф' in bad_vectorizer.vocabulary_)  # True

X_train_bad = X_all[:len(X_train)]
X_test_bad = X_all[len(X_train):]

bad_model = LogisticRegression(max_iter=1000)
bad_model.fit(X_train_bad, y_train)

# Правильно: fit только на train внутри Pipeline
pipe = Pipeline([
    ('tfidf', TfidfVectorizer()),
    ('clf', LogisticRegression(max_iter=1000))
])

pipe.fit(X_train, y_train)

vocab = pipe.named_steps['tfidf'].vocabulary_
print(len(vocab))          # 21
print('логарифм' in vocab) # False
print('эпиграф' in vocab)  # False

pred = pipe.predict(X_test)
print(pred)

Почему результат проверяемый? В train у нас 21 уникальный токен, а полный корпус содержит еще 6 слов из test, значит при неправильном порядке словарь вырастает до 27. Во втором случае словарь остается равным 21, потому что TfidfVectorizer не видел тестовые документы на этапе обучения. Это и есть граница, которую мы хотели сохранить.

Обратите внимание на поведение при предсказании: тестовые слова не ломают модель. Они просто не входят в словарь, а значит не дают новых признаков. Это нормально: модель не может использовать то, чему ее не учили. Для реальной задачи вы потом увеличите корпус, пересмотрите разбиение и выберете более устойчивую схему валидации, но порядок шагов останется тем же.

Как проверить границы обучения преобразований

Самая полезная проверка — не смотреть только на метрику, а проверить состояние обученного преобразования. Если у вас текстовая модель, загляните в словарь векторизатора, список отобранных признаков или статистики препроцессора. При ручной отладке удобно заранее выписать несколько слов, которые встречаются только в holdout-наборе, и убедиться, что после fit на train их нет в словаре. В учебном примере это логарифм и эпиграф.

Вторая проверка — посмотреть на код по шагам, а не на итоговый объект. Если вы видите конструкцию вроде vectorizer.fit_transform(X) до разделения, это повод остановиться сразу. Для scikit-learn полезное правило звучит жестко: все, что вызывает fit или fit_transform, должно получать train, а test проходит только через transform и потом через predict. Если вы используете кросс-валидацию, в нее нужно передавать сам Pipeline и сырые тексты, а не заранее подготовленную матрицу на всем корпусе.

  • Проверьте место, где происходит split: оно должно стоять раньше любого обучаемого преобразования.
  • Проверьте, есть ли в коде отдельные вызовы fit для test. Их не должно быть.
  • Проверьте объекты после обучения: словарь TF-IDF, статистики скейлера, выбранные признаки.
  • Проверьте кросс-валидацию: конвейер передается целиком, иначе утечка может прятаться до начала оценки.
  • Проверьте воспроизводимость: фиксируйте разбиение, чтобы сравнивать поведение до и после исправления порядка.

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

Что Pipeline не исправит сам по себе

Важно не перепутать две мысли. Первая: Pipeline хорошо защищает от утечки, связанной с порядком split - fit - transform. Вторая: это не означает отсутствие всех утечек вообще. Если один и тот же текст случайно попал и в train, и в test, если в данных есть почти дубли, если документы нужно делить по времени или по группам авторов, а вы разрезали их случайно, конвейер сам проблему не заметит. Он только корректно исполнит те шаги, которые вы ему дали.

Поэтому финальная проверка шире, чем одна векторизация. Спросите себя: нет ли в признаках сведений, которые появляются только после момента предсказания; нет ли технических меток в имени файла, колонке источника или шаблоне разметки; не смешаны ли версии одного и того же текста между выборками. Для коротких текстов полезно отдельно искать почти совпадающие записи, потому что они особенно легко завышают оценку качества.

Если хотите потренировать именно эту логику на более системной программе, посмотрите карточку курса по NLP в каталоге Азбуки курсов. По официальному описанию программы там есть разделение набора данных, кросс-валидация, оценка качества, а в блоке по обработке текстов — «мешок слов», TF-IDF и другие методы выделения признаков. Для темы утечек это полезно не как обещание результата, а как набор тем, на которых можно сознательно отработать правильный порядок подготовки выборок.

Курсы

147504
0,0
0 отзывов
Машинное обучение для анализа естественного языка (NLP)
  • С 8 сентября
  • 24 часа
  • с преподавателем
  • сертификат
42 000 ₽42 900 ₽
-2%
Перейти на сайт