Модуль 10. Аномалии: от z-score до леса

Цель модуля: научиться отвечать не на вопрос «кто выброс?», а на вопрос «что считать аномалией и что с ней делать». После модуля вы считаете z-score и IQR, понимаете, почему z-score ломается на собственных выбросах, знаете идею isolation forest для многомерных случаев и выбираете действие — алерт, сглаживание или отбрасывание — по контексту задачи.

Перед началом: модуль 2 (среднее, MSE и почему они боятся выбросов) и модуль 9 (аномалия — это «не похож на остальных»). Инструменты: песочница сайта (чистый Python), сниппет ниже. Трудоёмкость: ~1.5 ч (чтение 45 мин · сниппет и практика 35 мин).

🔥 Алерт стрелял ночью 40 раз

Порог алерта на p99 латентности — 200 мс. За ночь правило сработало сорок раз: график похож на кардиограмму, дежурный утром разбирает список, где тридцать девять записей — один и тот же инцидент с диском. Формально всё было выше порога, но 200 мс — почему и что вообще считать аномалией?

Порог отвечает на вопрос «когда тревожиться», но не на вопрос «что такое аномалия». Это два разных решения: статистическое (насколько значение необычно для распределения) и продуктовое (тревожить ли человека). Модуль разбирает оба.

📖 10.1. Порог — это решение, а не определение аномалии

Аномалия — отклонение от того, что ожидалось в этих условиях. Понедельник, десять утра, релизный день — пик нагрузки нормален; тот же пик в субботу — аномалия. «Ожидаемое» зависит от контекста, которого константа 200 мс не видит.

Отсюда первый шаг: определить, относительно чего мерить. Два частых ответа — «насколько значение далеко от среднего» (z-score) и «вне типичного диапазона» (IQR) — работают с одной метрикой против её истории. Второй тип аномалий — сочетание нормальных фич; о нём в 10.5, а сначала — одномерные инструменты.

📖 10.2. z-score: сколько сигм от среднего

z-score переводит значение в вопрос «на сколько сигм я дальше среднего»:

text
z = (x − среднее) / сигма

Правило трёх сигм: для нормального распределения за |z| > 3 лежит примерно 0.3% значений — их и объявляют выбросами. Одна формула, одно число, прямая интерпретация. Но у метода два смертельных изъяна на реальных данных.

Первый: среднее и сигма считаются по тем же данным, где сидит выброс. Выброс раздувает обе величины и прячется в раздутой сигме — логический круг. Сниппет это показывает буквально: сигма 1037.8 мс, значение 5000 мс — «всего» 4.46 сигмы, а реальная деградация 400 мс — 0.03 сигмы, то есть «норма». Метод оглушил сам себя.

Второй изъян мягче: гипотеза нормальности. Латентности и суммы платежей — распределения с тяжёлыми хвостами, и сигма их хвост не описывает. Для мониторинга берут медиану и квантили — то есть IQR из следующего раздела.

📖 10.3. IQR: квартили, которые не сдвигаются

IQR (interquartile range) строится на квартилях — это 25-й и 75-й процентили (Q1 и Q3). IQR = Q3 − Q1 — ширина «средней половины» данных. Границы Тьюки (из «ящика с усами» на box-plot):

text
[Q1 − 1.5 · IQR;  Q3 + 1.5 · IQR]

Всё за этими границами — кандидаты в выбросы. Ключевое свойство — робастность: квартили определяются порядком значений, а не их величиной. Один безумный замер не сдвинет Q1 и Q3: в сниппете границы [110.0; 134.0], хотя среднее тех же данных — 366.5 мс (испорчено, а квартили — нет).

Цена устойчивости: IQR отвечает «вне диапазона» — да или нет, — но не говорит, насколько далеко: 400 и 5000 для него одинаково «выше границы». Множитель 1.5 — соглашение, а не закон; по пяти точкам квартили бессмысленны.

📖 10.4. Сниппет: два метода на одних данных

Запустите outliers.py. В нём 21 замер p99: ровный ряд около 120 мс, деградация диска 400 мс в 17:04 и таймаут 5000 мс в 17:05. Вывод:

text
Замеров: 21, значения 110…5000 мс

Среднее = 366.5 мс, сигма = 1037.8 мс (выбросы раздувают обе цифры!)
 значение   z-score  вердикт |z|>3
     5000      4.46  ВЫБРОС
      400      0.03  норма
      130     -0.23  норма
      128     -0.23  норма
      126     -0.23  норма
      125     -0.23  норма

Q1 = 119.0, Q3 = 125.0, IQR = 6.0 → границы [110.0; 134.0]
     5000  ВЫБРОС (по IQR)
      400  ВЫБРОС (по IQR)
      130  норма (по IQR)
      128  норма (по IQR)
      126  норма (по IQR)
      125  норма (по IQR)

Читайте таблицу как детектив. 5000 мс — выброс у обоих методов. 400 мс — идеальный учебный контраст: z-score считает его нормой (z = 0.03), потому что сигма раздута до 1037.8 одним значением 5000; IQR объявляет выбросом, потому что 400 выше границы 134. Именно 400 мс — реальная деградация, ради которой всё и затевалось; метод, который её «не заметил», провалил бы ночной алерт. И мелочь: у значений 130, 128, 126, 125 z-score одинаковый до сотых (−0.23) — сигма в тысячу миллисекунд сжала весь рабочий диапазон в точку у среднего. Так выглядит потеря разрешения.

Вывод сниппета: это разные вопросы. z-score — «насколько я далеко от среднего», IQR — «вне типичного диапазона». Для мониторинга почти всегда берут второй; z-score полезен на чистых симметричных данных, где нужно «насколько».

📖 10.5. Когда порога мало: сочетания и идея isolation forest

Одномерные методы ловят «одна метрика против своей истории». Но аномалия часто — редкая комбинация нормальных значений: CPU 55% — обычный день, CPU 55% при упавшем вдвое трафике — подозрительно. Пороги по каждой оси такое не поймают: каждая координата по отдельности «в норме». Нужна мера «насколько точка далека от облака целиком» (по-взрослому — Mahalanobis или оценка плотности), и здесь в игру вступает isolation forest — метод, построенный на одной красивой идее.

Идея: аномалию легко изолировать. Возьмите случайные деревья: на каждом шаге выбирается случайная фича и случайный порог, точка уходит влево или вправо. Обычных точек много, и они похожи друг на друга — чтобы отделить одну от остальных, нужно много разрезов; аномалия одинока и сильно отличается — её отсекают от всех за пару шагов. Средняя длина пути по ансамблю деревьев становится скором: короткий путь — аномалия. Метод не требует разметки (аномалий обычно и нет в размеченном виде), не требует гипотезы нормальности и масштабируется. Родственная идея — One-class SVM: «обучиться на нормали и мерить удалённость от неё», дороже на больших данных.

Важная оговорка: лес выдаёт скор, а не вердикт — порог отсечения всё равно ваш, и порог аномалий — бюджет ложных тревог («сколько раз в неделю дежурный готов подняться зря»), ровно как порог классификатора (модуль 3) и метрик (модуль 7). В sklearn — IsolationForest в несколько строк; но берите его, когда сочетания фич реально бьют по одномерным порогам.

📖 10.6. Что делать с найденным: алерт, сглаживание, отбросить

Детекция нашла кандидатов. Дальше — решение по контексту, и вариантов три.

Алерт — выброс есть сигнал (латентность, деньги, ошибки). Правила: порог — по цене пропуска и цене ложной тревоги; группировать — сорок ночных срабатываний одной причины это один инцидент, а не сорок; хранить ответ «почему считаем аномалией», иначе дежурный не доверяет.

Сглаживание — выброс есть ошибка измерения. Для графиков и агрегатов: обрезать концы (winsorize), брать медиану вместо среднего, p95/p99 вместо максимума. Данные не исчезают — одно значение перестаёт определять итог.

Отбросить для обучения — выброс есть ошибка склейки или логов. Самый рискованный путь, и вот его правила: (1) сначала посмотрите на единичные выбросы глазами — 5000 мс из таймаута это реальность или артефакт складывания; (2) ошибку измерения/логирования исключать можно, а выброс-сигнал (мошенничество, сбой) — нельзя: вы выбросите то, что хотите предсказывать; (3) «модель на нём ошибается» — не повод выкинуть, это подгонка метрики; (4) правило живёт в коде пайплайна и одинаково применяется в обучении и в бою, иначе модель в бою встретит то, от чего её отучили (модуль 8).

И общая привычка: аномалии — не мусор, а наблюдения. Сохраняйте их отдельно и помечайте: через месяц вопрос «что случилось в 17:05» будет иметь ответ.

📖 10.7. Компромиссы

  • z-score vs IQR. z — число и интерпретация «насколько далеко», но ломается выбросами и гипотезой нормальности; IQR устойчив, но отвечает только «да/нет». Считайте оба: расхождение — самое интересное.
  • Порог vs алгоритм. Порог дёшев и объясним; алгоритм ловит сочетания, но требует данных и хуже объясняется. Начинайте с порогов по осям, лес — когда сочетания реально бьют.
  • Устойчивость vs чувствительность. Медиана и квартили дают меньше ложных тревог, но могут проспать раннюю деградацию; среднее заметит раньше, но разбудит зря. Классический обмен точности на полноту.
  • Удалять выбросы vs оставлять. Удаление чистит обучение, но может стереть редкий важный сигнал. Явная единая политика безопаснее ручной «чистки на глаз».
  • Автоматика vs человек в контуре. Полная автоматика тонет в тревогах, ручной контроль не масштабируется. Гибрид: автоматика ранжирует и группирует, человек решает.

💻 Практика

  1. (15 мин) Лечим z-score. Запустите outliers.py и уберите из LATENCY значение 5000. Пересчитайте: среднее упадёт до ~134.8 мс, сигма — до ~61.0, и 400 мс внезапно станет выбросом (z ≈ 4.35). Во сколько раз уменьшилась сигма и что это говорит про «круг» z-score?
  2. (15 мин) IQR руками. Для ряда (100, 102, 105, 110, 200, 101, 99, 103, 104) посчитайте Q1, Q3, IQR и границы. Кто выброс? Замените 200 на 10 000 — сдвинулись ли границы? Почему?
  3. (10 мин) Метрика своего сервиса. Для рабочей метрики (латентность, ошибки, конверсия) выпишите: что «норма», что «мягкая аномалия», что «тревога» и какие плановые события аномалией не считаются.
  4. (10 мин) Политика выбросов. Для задачи «срочный тикет» (модуль 3) решите: какие выбросы в фичах отбросите, какие превратите в признак-флаг «аномалия», и запишите решение правилом в одну строку.

🧩 Quiz "Проверь себя"

1. Почему в сниппете z-score не увидел 400 мс, а IQR увидел?
2. Что не так с порогом |z| > 3 как единственным правилом?
3. Чем принципиально отличается вопрос IQR от вопроса z-score?
4. Команда удаляет из обучающей выборки строки, на которых модель ошибается. Это…
5. Аномалия — «странная комбинация нормальных значений». Что ловит такое?

✅ Итоги модуля

  • Объяснить, почему порог — это решение, а не определение аномалии.
  • Посчитать z-score и IQR и показать на сниппете, где они расходятся (400 мс: норма у z, выброс у IQR).
  • Объяснить «круг» z-score: выбросы участвуют в тех же среднем и сигме.
  • Описать идею isolation forest: аномалия изолируется коротким путём.
  • Для своей метрики выписать плановые события, которые не аномалии.
  • Сформулировать политику выбросов для обучения и боя — одинаковую.

🔗 Мостик к Модулю 11

В этом модуле один и тот же набор данных дал два разных вердикта: всё решили определение и порог. Та же болезнь ждёт в оценке моделей: одна цифра на одной выборке умеет врать. Дальше — как мерить честно: k-fold, разброс вместо единственной цифры, подбор гиперпараметров и таблица «какая модель когда».