Как убрать выбросы в pandas

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Зачем это нужно

Выбросы — головная боль любого аналитика. Один клиент с покупкой на миллион искажает средний чек всей базы в 3 раза. 10 тестовых аккаунтов внутри команды ломают DAU. Чек 100 000 ₽ оказывается опечаткой кассира. Не обработали — сделали неверные выводы.

На собеседовании вопрос про outliers классический: «как найти и обработать?». Правильный ответ включает несколько методов — IQR, Z-score, percentile — и понимание, когда какой уместен. Плюс обязательно обсудить, нужно ли вообще удалять или это реальный сигнал.

В статье:

  • 3 метода детектирования (IQR, Z-score, percentile)
  • Winsorize как альтернатива удалению
  • Log-трансформация
  • Когда удалять, когда оставить
  • Код pandas для всех методов

1. Метод IQR (Inter-Quartile Range)

Самый робастный:

import pandas as pd

Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1

lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR

# пометить выбросы
df['is_outlier'] = (df['amount'] < lower) | (df['amount'] > upper)

# удалить
df_clean = df[(df['amount'] >= lower) & (df['amount'] <= upper)]

Коэффициент 1.5 — стандарт. Для более строгого — 3.0.

2. Z-score

import numpy as np

z = (df['amount'] - df['amount'].mean()) / df['amount'].std()
df['is_outlier'] = np.abs(z) > 3  # >3 SD от mean

df_clean = df[np.abs(z) <= 3]

Минус: сам mean и std зависят от outliers. IQR более надёжен.

3. Percentile

Прагматично: «топ 1% — выбросы»:

lower = df['amount'].quantile(0.01)
upper = df['amount'].quantile(0.99)

df_clean = df[(df['amount'] >= lower) & (df['amount'] <= upper)]

Или только с одной стороны:

# только big outliers
upper = df['amount'].quantile(0.99)
df_clean = df[df['amount'] <= upper]

4. Winsorize — не удалять, а «обрезать»

Заменяет экстремальные значения на границу (не удаляет строки):

from scipy.stats.mstats import winsorize

df['amount_winsorized'] = winsorize(df['amount'], limits=[0.01, 0.01])

Значения ниже P1 → P1. Выше P99 → P99. Сохраняет структуру, но смягчает хвосты.

5. Log-трансформация

Для данных с тяжёлым хвостом (revenue, время):

import numpy as np

df['amount_log'] = np.log1p(df['amount'])  # log(1+x) — safe для 0

Не убирает outliers, но делает их менее влиятельными. Хорошо для ML.

6. Multi-variate outliers

Один признак normal, но комбинация странная. Нужны ML-методы:

from sklearn.ensemble import IsolationForest

iso = IsolationForest(contamination=0.01)
df['is_outlier'] = iso.fit_predict(df[['amount', 'items_count']]) == -1

7. Per-group outliers

Outliers относительно группы, не глобально:

def detect_outliers(group):
    Q1 = group.quantile(0.25)
    Q3 = group.quantile(0.75)
    IQR = Q3 - Q1
    return (group < Q1 - 1.5*IQR) | (group > Q3 + 1.5*IQR)

df['is_outlier'] = df.groupby('category')['amount'].transform(detect_outliers)

«Выброс в Electronics» ≠ «выброс в Grocery» — разные масштабы.

8. Visualize перед удалением

import seaborn as sns

sns.boxplot(x=df['amount'])  # видно outliers как точки

Или histogram:

df['amount'].hist(bins=100)

Часто сразу становится понятно, настоящий ли outlier.

Когда НЕ удалять

1. Outlier — реальный сигнал

Whale-клиент дал 80% выручки. Удалять его = лгать.

2. Финансовые метрики

Для revenue total — все значения нужны.

3. ML для extreme cases

Обучаете model fraud detection — outliers это то, что нужно поймать.

4. Без понимания причины

Сначала выясните, почему outlier. Если баг — исправить в источнике. Если реальный — оставить.

Когда удалить / обработать

  • Opecatka в данных (миллион вместо тысячи)
  • Test / internal accounts
  • Boт / фрод
  • Для «типичного» описания

Для A/B-тестов

В A/B с тяжёлым хвостом (чек, session length) outliers искажают результат:

  1. Winsorize перед тестом (P99 → P99)
  2. Mann-Whitney вместо t-test
  3. Bootstrap для CI

Частые ошибки

1. Удалить outliers безальтернативно

«Удалил, среднее стало красивее». Потеряли информацию о реальном business.

2. Z-score на non-normal

Если данные скошены (lognormal), Z-score даёт неверные outliers.

3. Удалять по «круглым» числам

«Чек > 100 000 → выброс». Почему 100 000? Обоснуйте.

4. Не документировать

Через месяц никто не вспомнит, почему 200 записей удалено.

Связанные темы

FAQ

Какой метод лучше?

IQR для одномерных. Isolation Forest для многомерных.

Удалять или winsorize?

Winsorize сохраняет строки, меняет только extreme значения. Обычно предпочтительно.

Для ML — обрабатывать outliers?

Зависит от модели. Tree-based устойчивы. Linear — нет, надо.

В A/B обязательно?

Для heavy-tailed метрик — да.


Тренируйте pandas — откройте тренажёр с 1500+ вопросами для собесов.