Как найти выбросы в данных
Что такое выброс
Выброс (outlier) — значение, которое сильно отличается от остальных в выборке.
Примеры:
- Средний чек 1000₽, один заказ на 500 000₽ — выброс.
- Возраст пользователей 18–80, один 200 — выброс (ошибка).
- Температура 20°C, внезапно 50°C — сенсор сломался.
Зачем их находить
- Корректировать метрики. Один выброс двигает среднее, искажает AOV, ARPU.
- Обнаруживать баги. Возраст 200 или транзакция за год до регистрации — ошибка в данных.
- Антифрод. Подозрительно большая покупка — возможно мошенничество.
- ML-модели. Outliers ломают линейные модели.
Методы обнаружения
1. Z-score (для нормального распределения)
from scipy import stats
df['z'] = stats.zscore(df['amount'])
outliers = df[df['z'].abs() > 3]Строки с z > 3 (3σ от среднего) — выбросы.
Когда работает: данные распределены нормально.
Когда не работает: скошенные распределения (доход, LTV, время сессии).
2. IQR (универсальный)
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
outliers = df[(df['amount'] < lower) | (df['amount'] > upper)]Стандартный метод boxplot. Устойчив к скосу.
Visualize:
import seaborn as sns
sns.boxplot(data=df, x='amount')Точки вне «усов» — outliers.
3. Перцентили
lower = df['amount'].quantile(0.01)
upper = df['amount'].quantile(0.99)
outliers = df[(df['amount'] < lower) | (df['amount'] > upper)]Отсекаем 1% экстремумов с каждой стороны — простой метод.
4. Isolation Forest (ML)
from sklearn.ensemble import IsolationForest
iso = IsolationForest(contamination=0.01, random_state=42)
df['anomaly'] = iso.fit_predict(df[['amount', 'items_count']])
outliers = df[df['anomaly'] == -1]Работает с многомерными данными. Contamination = ожидаемая доля выбросов.
5. DBSCAN (clustering-based)
from sklearn.cluster import DBSCAN
db = DBSCAN(eps=0.5, min_samples=5)
df['cluster'] = db.fit_predict(df[['x', 'y']])
outliers = df[df['cluster'] == -1]Точки, не попавшие в кластеры — выбросы.
6. Визуально — scatter plot
import seaborn as sns
sns.scatterplot(data=df, x='price', y='amount')Точки далеко от общего облака — выбросы.
Тренироваться на таких вопросах можно в Telegram-боте Карьерник — там 1500+ задач с реальных собесов с разборами.
В SQL
IQR в SQL
WITH bounds AS (
SELECT
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY amount) AS q1,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY amount) AS q3
FROM orders
)
SELECT o.*
FROM orders o, bounds b
WHERE o.amount < b.q1 - 1.5 * (b.q3 - b.q1)
OR o.amount > b.q3 + 1.5 * (b.q3 - b.q1);Z-score в SQL
WITH stats AS (
SELECT AVG(amount) AS mu, STDDEV(amount) AS sd FROM orders
)
SELECT o.*,
(o.amount - s.mu) / s.sd AS z_score
FROM orders o, stats s
WHERE ABS((o.amount - s.mu) / s.sd) > 3;Что делать с выбросами
1. Удалить
df_clean = df[~df.index.isin(outliers.index)]Подходит, если:
- Это ошибка в данных.
- Выбросов мало.
- Выбросы не важны для анализа.
2. Обрезать (winsorize)
from scipy.stats import mstats
df['amount_clipped'] = mstats.winsorize(df['amount'], limits=[0.01, 0.01])Значения > p99 становятся p99. Сохраняем строки, убираем влияние.
3. Заменить
median = df['amount'].median()
df.loc[outlier_mask, 'amount'] = medianКомпромисс: строка остаётся, но значение «исправлено».
4. Логарифмировать
df['log_amount'] = np.log1p(df['amount'])Для скошенных распределений — логарифм делает их ближе к нормальному, выбросы становятся менее влиятельными.
5. Анализировать отдельно
Иногда выбросы — это важная группа («киты» в LTV, фрод-транзакции). Не удалять, а изучать отдельно.
Как решать, что делать
Удалять, если
- Ошибка данных (возраст 200).
- Выбросов < 1% и они мешают анализу.
- Для ML обучения линейных моделей.
Оставить, если
- Выбросы — реальные данные (киты-пользователи).
- В медиане и p95 сохраняется смысл.
- Анализ робастный к выбросам.
Логарифмировать, если
- LTV, revenue, income — скошенные распределения.
- Хотите сохранить всю информацию.
- Строите regression модель.
К слову, набить руку на таких кейсах удобно через тренажёр в Telegram — разбирайте по 10 вопросов в день, через 2 недели тема становится рефлексом.
Типичные ошибки
1. Удалять выбросы без проверки
«Выбросы» могут быть настоящими power-users, приносящими 80% revenue. Удалите — разрушите бизнес-логику.
2. Использовать среднее + std для скошенных данных
Mean и std сами искажены выбросами. Используйте median и IQR.
3. Игнорировать многомерность
Точка может быть нормальной по каждой колонке, но аномальной в паре. Используйте Isolation Forest.
4. Не визуализировать
Всегда сначала boxplot / scatter — глаз лучше любого алгоритма.
Читайте также
- Выбросы в данных
- Z-score в статистике
- Как очистить данные в pandas
- Медиана vs среднее
- Bootstrap в статистике
FAQ
Z-score или IQR?
IQR для скошенных распределений (обычная ситуация). Z-score для нормальных.
Isolation Forest сложный?
Нет. 3 строки кода через sklearn. Хорошо работает из коробки.
Всегда удалять выбросы перед анализом?
Нет. Сначала понять, что они значат. В некоторых бизнесах outliers — это главное.
Как быть с выбросами в A/B-тесте?
Либо тримминг/winsorization (обрезка p99), либо Mann-Whitney U test (устойчив к выбросам), либо CUPED.