Предиктив пропустил аварию при ROC-AUC 0.94: разбор инцидента и почему offline-метрика врёт — это не выдуманный сценарий, а фабула типичного пост-мортема на современном производстве. Три месяца назад вендор сдал пилот. В отчёте сиял высочайший AUC, графики сходились, акт приёмки был подписан. Вчера главный магистральный насос встал колом. Минус целая смена, сорванный план по сырью и полмиллиона на срочный ремонт. До самого момента хруста вала алгоритм упрямо рисовал вероятность отказа на уровне 0.05. Это чистый предиктив отказов оборудования провал, корень которого лежит не в архитектуре нейросети, а в чудовищной методологии оценки.
Хронология: как железо кричало о помощи, а модель спала
Отмотаем логи на сутки назад. Датчики вибрации (RMS) показывали медленный, но уверенный рост с 2.1 до 4.5 мм/с. Датчики тока на приводе фиксировали рваные гармоники. Опытный обходчик напрягся бы от одного звука, но мы же купили ИИ, который должен видеть невидимое. Почему предиктивная модель пропустила аварию? Потому что её обучали на стерильном прошлом, из которого случайным образом выдрали куски для теста. Алгоритм просто не распознал паттерн, так как находился в слепой зоне своей архитектуры валидации.
Data leakage в обучении и экстраполяция в пустоту
Разбирая логи подрядчика, мы сразу наткнулись на классику жанра: random split. Дата-саентисты перемешали исторические ряды за год и откусили 20% на валидацию. Для временных рядов это гарантированный data leakage в обучении. Модель нагло подглядывала в будущее, запоминая макро-режимы оборудования. Добило всё применение StandardScaler сразу ко всему датасету до разбиения — признаки из будущего математически просочились в обучающую выборку. Модель стала гениальной на бумаге.
А на проде случился concept drift (дрейф концепта). Ночью технологи пустили сырьё другой плотности. Нагрузка на вал выросла, распределение фич уехало далеко вправо. Нейронка, никогда не видевшая таких значений в своём перемешанном парнике, начала экстраполировать в пустоту и выдала уверенный нуль.
Метрики предиктивного обслуживания: ROC-AUC против сгоревших денег
Оптимизировать ROC-AUC в системах ТОиР — это техническое вредительство. Дата-саентист радуется площади под кривой, а главный механик седеет. Модель может блестяще угадывать 99% фонового шума и микро-колебаний, но пропускает один катастрофический отказ, который стоит как крыло самолёта. Или угадывает, но за шесть минут до клина подшипника. Что оператор сделает за шесть минут? Успеет нажать кнопку экстренного останова, если не отойдёт за кофе.
Адекватные метрики предиктивного обслуживания обязаны быть привязаны к физике и экономике цеха. Нас интересует исключительно recall (полнота) на критических, самых дорогих отказах и lead-time предупреждения. Поймать разрушение за 6 часов до часа икс — это победа, позволяющая перевести нагрузку на резерв. Поймать за 6 минут — это просто красивый лог перед неизбежным пожаром.
from sklearn.model_selection import TimeSeriesSplit
class GapTimeSeriesSplit(TimeSeriesSplit):
# Временная валидация модели: отрезаем мертвую зону (gap),
# чтобы избежать утечки данных между трейном и тестом
def __init__(self, n_splits=5, gap_hours=24, window_size=168):
super().__init__(n_splits=n_splits)
self.gap = gap_hours
self.window = window_size
def split(self, X, y=None, groups=None):
for train_idx, test_idx in super().split(X, y, groups):
valid_train = train_idx[:-self.gap]
valid_test = test_idx[:self.window]
if len(valid_train) > 0 and len(valid_test) > 0:
yield valid_train, valid_testСуровая приёмка и мониторинг дрейфа
Когда мы в Morana Labs катили предиктив на компрессорных станциях, мы выкинули классическую кросс-валидацию в первый же день. Строго временная валидация модели (rolling/expanding window) с мёртвой зоной между обучающей и тестовой выборкой — единственный способ понять реальную предсказательную силу алгоритма. На проде критически необходим мониторинг дрейфа фич через PSI (Population Stability Index) или KL-дивергенцию. Как только распределение тока или вибрации уезжает за исторические лимиты, система должна бить тревогу, блокировать предсказания как ненадёжные и запрашивать переобучение.
Чтобы ваш следующий пилот не закончился порванным железом, заставьте вендора пройти жёсткий чек-лист, состоящий из семи пунктов, доказывающих, почему вашему предиктиву нельзя верить по одному ROC-AUC. Первый шаг: требуйте показать схему разбиения данных — если там нет строгой оси времени, гоните исполнителя в шею. Второй: проверьте, где и как обучался скейлер нормализации, чтобы исключить утечку глобальных максимумов в трейн. Третий: запросите матрицу ошибок, построенную исключительно на дорогих отказах, отфильтровав мелкие плановые остановки. Четвёртый: требуйте график зависимости recall от горизонта прогнозирования, чтобы убедиться, что модель ловит отказы хотя бы за несколько часов. Пятый: задайте вопрос, как пайплайн обрабатывает NaN-значения и отвалы самих датчиков, чтобы алгоритм не сошёл с ума от тишины в логах. Шестой: убедитесь в наличии автоматического алерта на дрейф входных данных при смене режима работы агрегата. Седьмой: впишите в SLA не абстрактные датасаентистские проценты, а целевую долю пойманных аварий умноженную на средний lead-time в часах.
Предиктив оценивается сохранёнными подшипниками, спасёнными агрегатами и часами резерва, а не синтетической оффлайн-величиной. Требуйте жесткого аудита методологии валидации и немедленной постановки мониторинга дрейфа для вашей модели, пока она не пропустила очередной удар.