Исправили разметку — выросла метрика: как отделить улучшение модели от смены теста

После очистки тестовой выборки accuracy выросла с 70% до 80%. Команда записывает улучшение в результат новой модели. Но одновременно исправились ответы разметчиков, изменился состав документов и обновился код. Из одного числа нельзя понять, что именно стало лучше и стоит ли выпускать модель.

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

Заморозим то, что уже получено

Сохраните предсказания обеих моделей по идентификаторам объектов, версии исходных файлов и обе версии меток. Если порядок строк в выгрузке изменился, сравнивайте по ID. Не подставляйте новые ответы к старому массиву предсказаний по позиции: тогда ошибка соответствия станет похожа на изменение качества.

В журнал исправлений включите старую метку, новую, причину и ссылку на исходный объект. Причины полезно различать: опечатка, неверное правило, неоднозначный случай, изменение бизнес-определения. Последнее может означать новую задачу. Например, «отток за 30 дней» и «отток за 60 дней» требуют самостоятельной приёмки, даже если имена классов совпали.

Четыре оценки вместо двух

Оцените старую и новую модель на старом эталоне, затем обе на исправленном. Так станет видно, какое улучшение произошло из-за смены меток и какой вариант выигрывает при одинаковом понимании правильного ответа. Для принятия текущего решения главным становится исправленный эталон, если он соответствует действующей постановке.

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

import pandas as pd
d = pd.DataFrame({
    'id':['d1','d2','d3','d4','d5','d6'],
    'label_v1':[0,0,1,1,0,1],
    'label_v2':[0,1,1,1,0,0],
    'old_model':[0,1,1,0,0,0],
    'new_model':[0,1,1,1,1,0],
})
assert d.id.is_unique
for labels in ['label_v1','label_v2']:
    for model in ['old_model','new_model']:
        correct = int(d[model].eq(d[labels]).sum())
        print(labels, model, 'correct', correct, 'accuracy', round(correct/len(d), 4))
changed = d.loc[d.label_v1 != d.label_v2]
disagree = d.loc[d.old_model != d.new_model]
print('changed_labels', changed.id.tolist())
print('model_disagreement', disagree.id.tolist())
print('new_wins_v2', disagree.loc[disagree.new_model == disagree.label_v2, 'id'].tolist())
print('old_wins_v2', disagree.loc[disagree.old_model == disagree.label_v2, 'id'].tolist())
assert changed.id.tolist() == ['d2','d6']
assert d.old_model.eq(d.label_v2).sum() == 5
assert d.new_model.eq(d.label_v2).sum() == 5

На старой разметке обе модели имеют три правильных ответа из шести. На исправленной — пять из шести. Рост с 50% до примерно 83,3% объясняется исправлением меток и одинаково относится к обеим системам. У новой модели нет преимущества по accuracy: она исправила d4 и одновременно испортила d5.

Это не означает, что варианты равноценны для бизнеса. Если ошибка d4 намного дороже ошибки d5, новое решение может быть полезнее. Тогда обсудите стоимость конкретных типов ошибок и посчитайте согласованный показатель на одном эталоне. Изменение определения успеха должно быть видно в отчёте, а не появляться после неудобного результата.

Как исправление теста может породить новый перекос

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

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

Объекты, которые пока не удалось согласовать, отметьте отдельным статусом. Не удаляйте их из теста только потому, что они ухудшают результат. Сохраните число исключений и причину, а также проверьте, встречаются ли такие случаи в будущем потоке. Возможно, продукту нужен путь ручного решения для неоднозначных документов.

Как выпускать новую версию проверочного набора

Сделайте отдельную версию данных с неизменяемыми ID и журналом изменений. Пересчитайте на ней несколько важных прошлых моделей. Это восстановит сопоставимый ряд экспериментов: станет видно, изменился рейтинг кандидатов или только абсолютные значения метрик. В отчёте релиза указывайте и версию модели, и версию эталона.

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

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

Проверьте также полноту соответствия ID: документ, исчезнувший при очистке, должен иметь записанную причину исключения. Иначе улучшение может оказаться результатом удаления трудных примеров.

В платном курсе «ML Engineer / Data Scientist: табличные модели в продакшн» вы собираете воспроизводимый pipeline обучения, сравниваете модели и разбираете ошибки перед batch-инференсом и API. Откройте программу курса, чтобы связать версии данных, таблицу экспериментов и решение о релизе в одном рабочем процессе.

Продолжить на практике

  • ML Engineer / Data Scientist: табличные модели в продакшн ↗

    Практический курс для тех, кто хочет получить навыки ML Engineer / Data Scientist на реальных табличных задачах. В курсе Вы не просто обучите CatBoost/LightGBM, а соберёте полноценный production-style пайплайн: подготовка данных, feature engineering (генерация признаков), корректная валидация, защита от leakage (утечек), тюнинг через Optuna, интерпретация через SHAP, batch-инференс и REST API для предсказаний.