Зачем нужна робастная статистика?
Стандартное отклонение — мощная мера разброса, но у неё есть критическая слабость: крайняя чувствительность к выбросам. Одно экстремальное значение может резко завысить СО, давая искажённое представление о типичной вариации.
Робастная статистика предоставляет меры разброса, устойчивые к влиянию выбросов, что делает их незаменимыми для реальных данных, где часто встречаются ошибки измерений, ошибки ввода или подлинные экстремальные случаи.
Пример: Влияние выброса
Точка разрушения
Медианное абсолютное отклонение (MAD)
MAD — наиболее робастная мера разброса. Она вычисляет медиану абсолютных отклонений от медианы:
Формула MAD
Найдите медиану
Рассчитайте отклонения
Найдите MAD
Масштабирование MAD для оценки σ: Для нормально распределённых данных MAD ≈ 0,6745 × σ. Для оценки СО по MAD умножьте на 1,4826:
Оценка СО через MAD
Почему 1,4826?
Межквартильный размах (IQR)
IQR измеряет разброс средних 50% данных — расстояние между 25-м и 75-м процентилями:
Формула IQR
IQR широко используется, потому что прост для понимания, легко визуализируется на диаграммах размаха и является основой распространённого правила «1,5×IQR» для обнаружения выбросов.
Масштабирование IQR для оценки σ: Для нормальных данных IQR ≈ 1,35 × σ. Для оценки СО по IQR:
Оценка СО через IQR
Сравнение робастных мер
Стандартное отклонение
MAD
IQR
Когда использовать робастную статистику
- Разведочный анализ: когда неизвестно, есть ли выбросы, начните с робастных мер
- Проблемы качества данных: когда данные могут содержать ошибки или проблемы измерений
- Тяжелохвостые распределения: когда экстремальные значения ожидаемы (финансовая доходность, страховые выплаты)
- Малые выборки: когда выбросы оказывают непропорционально большое влияние из-за малого числа наблюдений
- Обнаружение выбросов: использование СО для обнаружения выбросов — логический круг; вместо этого используйте IQR или MAD
Примеры реализации
import numpy as np
from scipy import stats
def mad(data):
"""Median Absolute Deviation"""
median = np.median(data)
return np.median(np.abs(data - median))
def scaled_mad(data):
"""MAD scaled to estimate SD (for normal data)"""
return 1.4826 * mad(data)
def iqr(data):
"""Interquartile Range"""
return np.percentile(data, 75) - np.percentile(data, 25)
# Compare on data with outlier
data = [10, 12, 11, 13, 12, 11, 100]
print(f"SD: {np.std(data, ddof=1):.2f}")
print(f"MAD: {mad(data):.2f}")
print(f"Scaled MAD: {scaled_mad(data):.2f}")
print(f"IQR: {iqr(data):.2f}")