Предиктив пропустил аварию при 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Суровая приемка и мониторинг дрейфа
Когда мы в MoranaLabs катили предиктив на компрессорных станциях, мы выкинули классическую кросс-валидацию в первый же день. Строго временная валидация модели (rolling/expanding window) с мертвой зоной между обучающей и тестовой выборкой — единственный способ понять реальную предсказательную силу алгоритма. На проде критически необходим мониторинг дрейфа фич через PSI (Population Stability Index) или KL-дивергенцию. Как только распределение тока или вибрации уезжает за исторические лимиты, система должна бить тревогу, блокировать предсказания как ненадежные и запрашивать переобучение.
Чтобы ваш следующий пилот не закончился порванным железом, заставьте вендора пройти жесткий чек-лист, состоящий из семи пунктов, доказывающих, почему вашему предиктиву нельзя верить по одному ROC-AUC. Первый шаг: требуйте показать схему разбиения данных — если там нет строгой оси времени, гоните исполнителя в шею. Второй: проверьте, где и как обучался скейлер нормализации, чтобы исключить утечку глобальных максимумов в трейн. Третий: запросите матрицу ошибок, построенную исключительно на дорогих отказах, отфильтровав мелкие плановые остановки. Четвертый: требуйте график зависимости recall от горизонта прогнозирования, чтобы убедиться, что модель ловит отказы хотя бы за несколько часов. Пятый: задайте вопрос, как пайплайн обрабатывает NaN-значения и отвалы самих датчиков, чтобы алгоритм не сошел с ума от тишины в логах. Шестой: убедитесь в наличии автоматического алерта на дрейф входных данных при смене режима работы агрегата. Седьмой: впишите в SLA не абстрактные датасаентистские проценты, а целевую долю пойманных аварий умноженную на средний lead-time в часах.
Предиктив оценивается сохраненными подшипниками, спасенными агрегатами и часами резерва, а не синтетической оффлайн-величиной. Требуйте жесткого аудита методологии валидации и немедленной постановки мониторинга дрейфа для вашей модели, пока она не пропустила очередной удар.