← Назад к вопросам

Как выявить и обработать выбросы (outliers) в данных?

1.7 Middle🔥 171 комментариев
#Pandas и обработка данных#Статистика и теория вероятностей

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как выявить и обработать выбросы (outliers) в данных?

Выброс (outlier) — это значение, которое значительно отличается от остальных данных в наборе. Выбросы могут возникать из-за ошибок измерения, опечаток в данных, или редких, но легальных событий. Для Data Analyst правильно выявлять и обрабатывать выбросы критично, так как они могут исказить анализ и привести к неправильным выводам.

Почему выбросы проблематичны:

  1. Искажение статистики — выбросы увеличивают среднее, дисперсию, стандартное отклонение
  2. Влияние на модели — регрессионные модели очень чувствительны к выбросам
  3. Неправильные выводы — выбросы могут привести к ложным выводам о данных
  4. Инфляция показателей — средние и суммы становятся неправдоподобными
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Пример: данные с выбросом
data = [100, 105, 102, 103, 104, 101, 102, 99, 101, 5000]  # 5000 — выброс!

print(f'Среднее без анализа: {np.mean(data):.2f}')  # 551.7 (неправильно!)
print(f'Медиана без анализа: {np.median(data):.2f}')  # 101.5 (правильно)
print(f'Стандартное отклонение: {np.std(data):.2f}')  # 1577 (очень завышено)

Метод 1: IQR (Interquartile Range)

Это самый популярный метод, основанный на квартилях.

Формула:

  • Q1 — первый квартиль (25-й процентиль)
  • Q3 — третий квартиль (75-й процентиль)
  • IQR = Q3 - Q1
  • Выброс если: X < Q1 - 1.5×IQR или X > Q3 + 1.5×IQR
import numpy as np
import pandas as pd

# Данные
data = pd.Series([100, 105, 102, 103, 104, 101, 102, 99, 101, 5000])

# Рассчитать квартили
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1

print(f'Q1: {Q1}')
print(f'Q3: {Q3}')
print(f'IQR: {IQR}')

# Определить границы
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

print(f'Нижняя граница: {lower_bound}')
print(f'Верхняя граница: {upper_bound}')

# Найти выбросы
outliers = data[(data < lower_bound) | (data > upper_bound)]
print(f'Выбросы: {outliers.values}')

# Или использовать встроенный метод pandas
print(f'\nБез выбросов:')
data_clean = data[(data >= lower_bound) & (data <= upper_bound)]
print(data_clean.values)

Метод 2: Z-score (стандартное отклонение)

Базируется на расстоянии в стандартных отклонениях от среднего.

Формула:

z = (x - mean) / std

Обычно считаем выбросом если |z| > 3 (или > 2.5 для более строгого критерия).

from scipy import stats
import numpy as np

data = np.array([100, 105, 102, 103, 104, 101, 102, 99, 101, 5000])

# Рассчитать z-score
z_scores = np.abs(stats.zscore(data))

print(f'Z-scores: {z_scores}')

# Найти выбросы (|z| > 3)
threshold = 3
outlier_mask = z_scores > threshold
outliers = data[outlier_mask]

print(f'Выбросы (|z| > 3): {outliers}')
print(f'Индексы выбросов: {np.where(outlier_mask)[0]}')

# Более мягкий критерий: |z| > 2.5
threshold = 2.5
outlier_mask = z_scores > threshold
outliers = data[outlier_mask]
print(f'\nВыбросы (|z| > 2.5): {outliers}')

Метод 3: Метод изоляции (Isolation Forest)

Машинное обучение подход для обнаружения выбросов в многомерных данных.

from sklearn.ensemble import IsolationForest
import numpy as np
import pandas as pd

# Многомерные данные
X = pd.DataFrame({
    'age': [25, 30, 28, 32, 29, 26, 31, 100, 27, 29],  # 100 — возможный выброс
    'income': [50000, 60000, 55000, 65000, 58000, 52000, 62000, 55000, 59000, 61000]
})

# Обучить модель (contamination — предполагаемая доля выбросов)
iso_forest = IsolationForest(contamination=0.1, random_state=42)
predictions = iso_forest.fit_predict(X)

# -1 означает выброс, 1 — нормальное значение
X['is_outlier'] = predictions

print(X[X['is_outlier'] == -1])

Метод 4: MAD (Median Absolute Deviation)

Робустный метод, менее чувствительный к экстремальным выбросам.

import numpy as np
from scipy.stats import median_abs_deviation

data = np.array([100, 105, 102, 103, 104, 101, 102, 99, 101, 5000])

# Рассчитать MAD
median = np.median(data)
mad = median_abs_deviation(data)

print(f'Медиана: {median}')
print(f'MAD: {mad}')

# Выброс если: |x - median| > 3 * MAD
threshold = 3
outlier_mask = np.abs(data - median) > threshold * mad
outliers = data[outlier_mask]

print(f'Выбросы: {outliers}')

Обработка выбросов:

После выявления нужно решить, что с ними делать.

Вариант 1: Удаление

Просто исключить выбросы из анализа (если они явно ошибки).

import pandas as pd

df = pd.DataFrame({
    'sales': [100, 105, 102, 103, 104, 101, 102, 99, 101, 5000],
    'date': pd.date_range('2024-01-01', periods=10)
})

# Удалить выбросы (IQR метод)
Q1 = df['sales'].quantile(0.25)
Q3 = df['sales'].quantile(0.75)
IQR = Q3 - Q1

df_clean = df[(df['sales'] >= Q1 - 1.5*IQR) & (df['sales'] <= Q3 + 1.5*IQR)]
print(df_clean)

Вариант 2: Трансформация

Применить логарифм или корень для сжатия диапазона значений.

import numpy as np

data = np.array([100, 105, 102, 103, 104, 101, 102, 99, 101, 5000])

# Логарифмическая трансформация
log_data = np.log(data)
print(f'Оригинальные данные: {data}')
print(f'После log: {log_data}')

# Квадратный корень
sqrt_data = np.sqrt(data)
print(f'После sqrt: {sqrt_data}')

Вариант 3: Winsorization

Заменить экстремальные значения на граничные.

from scipy.stats.mstats import winsorize
import numpy as np

data = np.array([100, 105, 102, 103, 104, 101, 102, 99, 101, 5000])

# Winsorize: заменить top/bottom 10% на 90th/10th процентили
winsorized = winsorize(data, limits=0.1)
print(f'Оригинальные: {data}')
print(f'Winsorized: {winsorized}')

Вариант 4: Заполнение медианой/средним

Заменить выбросы на статистику (медиану или среднее).

import pandas as pd
import numpy as np

df = pd.DataFrame({'value': [100, 105, 102, 103, 104, 101, 102, 99, 101, 5000]})

# Найти выбросы
Q1 = df['value'].quantile(0.25)
Q3 = df['value'].quantile(0.75)
IQR = Q3 - Q1

outlier_mask = (df['value'] < Q1 - 1.5*IQR) | (df['value'] > Q3 + 1.5*IQR)

# Заменить на медиану
median = df['value'].median()
df.loc[outlier_mask, 'value'] = median

print(df)

Практический пример: Анализ продаж

import pandas as pd
import numpy as np
from scipy import stats

# Данные о суточных продажах
df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=100),
    'sales': np.random.normal(1000, 100, 100)  # Нормальные данные
})

# Добавить выбросы (выходные с низкими продажами)
df.loc[[10, 50, 75], 'sales'] = [200, 150, 180]

# Добавить выброс (день распродажи с высокими продажами)
df.loc[30, 'sales'] = 5000

print(f'Среднее с выбросами: {df["sales"].mean():.2f}')
print(f'Медиана: {df["sales"].median():.2f}')

# Обнаружить выбросы
Q1 = df['sales'].quantile(0.25)
Q3 = df['sales'].quantile(0.75)
IQR = Q3 - Q1

outlier_mask = (df['sales'] < Q1 - 1.5*IQR) | (df['sales'] > Q3 + 1.5*IQR)
outliers = df[outlier_mask]

print(f'\nНайдено выбросов: {len(outliers)}')
print(outliers)

# Анализ: естественный ли выброс?
for idx, row in outliers.iterrows():
    if row['sales'] < Q1 - 1.5*IQR:
        print(f"Дата {row['date'].date()}: низкие продажи (возможно выходной)")
    else:
        print(f"Дата {row['date'].date()}: высокие продажи (возможно специальное событие)")

# Очищенные данные
df_clean = df[~outlier_mask]
print(f'\nСреднее после удаления выбросов: {df_clean["sales"].mean():.2f}')

Чек-лист для Data Analyst:

✅ Визуализируй данные (box plot, histogram, scatter plot) — выбросы видны глазом ✅ Используй IQR для быстрого обнаружения ✅ Используй Z-score для нормально распределённых данных ✅ Используй Isolation Forest для многомерных данных ✅ ВСЕГДА исследуй выброс перед удалением — может быть важный сигнал ✅ Документируй решение: что ты делал с выбросами и почему ✅ Повтори анализ с/без выбросов — посмотри, как они влияют на результаты ✅ Не удаляй слепо — оцени бизнес-контекст

Выводы:

  • IQR — самый простой и надёжный метод
  • Z-score — хорош для нормальных распределений
  • Isolation Forest — лучше для многомерных данных
  • Всегда исследуй выброс перед обработкой
  • Не удаляй автоматически — выброс может быть бизнес-информацией
  • Документируй свои решения по обработке выбросов

Правильная работа с выбросами — это балансирование между чистотой данных и потерей информации.

Как выявить и обработать выбросы (outliers) в данных? | PrepBro