Метки есть только у проверенных заявок: почему тест не представляет поток

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

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

Сначала восстановите путь к метке

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

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

Вычислим, какую аудиторию представляет тест

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

import pandas as pd
d = pd.DataFrame({
    'segment': ['обычные', 'сложные'],
    'arrived': [9000, 1000],
    'reviewed': [100, 500],
    'correct': [98, 350],
})
d['accuracy'] = d.correct / d.reviewed
d['review_rate'] = d.reviewed / d.arrived
d['traffic_share'] = d.arrived / d.arrived.sum()
archive_accuracy = d.correct.sum() / d.reviewed.sum()
reweighted = (d.accuracy * d.traffic_share).sum()
print(d.to_string(index=False))
print('archive_accuracy', round(archive_accuracy, 4))
print('traffic_weighted_assuming_representative', round(reweighted, 4))
assert abs(archive_accuracy - 448/600) < 1e-12
assert abs(reweighted - 0.952) < 1e-12

Архив даёт около 74,67% правильных решений, а пересчёт по составу потока — 95,2%. Разница велика, но второе число пока нельзя печатать как доказанную точность сервиса. Возможно, из обычных заявок сотрудникам показывали только те, где старое правило заметило редкую ошибку. Тогда даже внутри сегмента сохранился отбор по сложности, которого два столбца отчёта не описывают.

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

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

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

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

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

Как объяснить результат заказчику

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

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

Чтобы довести такую работу до модели, нужны корректная постановка цели и воспроизводимая валидация. В платном курсе «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 для предсказаний.