Обнаружение статистических выбросов в Python - LEFT JOIN

Свяжитесь с нами в любой удобной для вас форме

Менеджер

Написать в телеграмм

Онлайн
Телеграмм
или
Заполните форму

3 минут чтения

*

24 марта 2021 г.

Обнаружение статистических выбросов в Python

Параллельно с выходом материала «Обнаружение выбросов в R» предлагаем посмотреть, как те же методы обнаружения выбросов реализовать в Python.

Данные

Для наглядности эксперимента возьмём тот же пакет данных mpg — скачать его в виде csv-таблицы можно с GitHub. Импортируем библиотеки и читаем таблицу в DataFrame:



import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_csv(‘mpg.csv’)

Минимальные и максимальные значения

Тут всё просто. Выводим описание всего датасета методом describe():



df.describe()

Гистограмма

Такой график тоже можно построить в одну строку, используя внутренние средства библиотеки pandas:



df.hwy.plot(kind=’hist’, density=1, bins=20, stacked=False, alpha=.5, color=’grey’)

Box plot

В случае ящика с усами далеко идти тоже не приходится — в pandas есть метод и для этого:



_, bp = df.hwy.plot.box(return_type=’both’)

Получим точки с графика и выведем их в таблице, используя объект bp:



outliers = [flier.get_ydata() for flier in bp[«fliers»]][0]
df[df.hwy.isin(outliers)]

Процентили

При помощи метода quantile получаем соответствующую нижнюю и верхнюю границы, а затем выводим всё, что выходит за их рамки:



lower_bound = df.hwy.quantile(q=0.025)
upper_bound = df.hwy.quantile(q=0.975)
df[(df.hwy < lower_bound) | (df.hwy > upper_bound)

Фильтр Хэмпеля

Мы используем реализацию фильтра Хэмпеля, найденную на StackOverflow

Опишем функцию, которая заменяет на nan все значения, у которых разница с медианой больше, чем три медианных абсолютных отклонения.




def hampel(vals_orig):
    vals = vals_orig.copy()
    difference = np.abs(vals.median()-vals)
    median_abs_deviation = difference.median()
    threshold = 3 * median_abs_deviation
    outlier_idx = difference > threshold
    vals[outlier_idx] = np.nan
    return(vals)

И применим к нашему набору данных:



hampel(df.hwy)0 29.0

1 29.0
2 31.0
3 30.0
4 26.0
…
229 28.0
230 29.0
231 26.0
232 26.0
233 26.0
Name: hwy, Length: 234, dtype: float64

В выводе нет nan-значений, а значит и выбросов фильтр Хэмпеля не обнаружил.

Тест Граббса

Автор реализации теста Граббса и теста Рознера для Python

Опишем три функции: первая находит значение критерия Граббса и максимальное значение в наборе данных, вторая — критическое значение с учётом объёма выборки и уровня значимости, а третья проверяет, является ли значение с максимальным индексом выбросом:



import numpy as np
from scipy import stats
def grubbs_stat(y):
std_dev = np.std(y)
avg_y = np.mean(y)
abs_val_minus_avg = abs(y — avg_y)
max_of_deviations = max(abs_val_minus_avg)
max_ind = np.argmax(abs_val_minus_avg)
Gcal = max_of_deviations / std_dev
print(f»Grubbs Statistics Value: {Gcal}»)
return Gcal, max_ind


def calculate_critical_value(size, alpha):
    t_dist = stats.t.ppf(1 — alpha / (2 * size), size — 2)
    numerator = (size — 1) * np.sqrt(np.square(t_dist))
    denominator = np.sqrt(size) * np.sqrt(size — 2 + np.square(t_dist))
    critical_value = numerator / denominator<br>
    print(f»Grubbs Critical Value: {critical_value}»)
    return critical_value
def check_G_values(Gs, Gc, inp, max_index):
    if Gs > Gc:
        print(f»{inp[max_index]} is an outlier»)
    else:
        print(f»{inp[max_index]} is not an outlier»)


Заменим значение в 34 строке на 212:



df.hwy[34] = 212

И выполним три функции:



Gcritical = calculate_critical_value(len(df.hwy), 0.05)
Gstat, max_index = grubbs_stat(df.hwy)
check_G_values(Gstat, Gcritical, df.hwy, max_index)

Grubbs Critical Value: 3.652090929984981

Grubbs Statistics Value: 13.745808761040397
212 is an outlier

Тест Рознера

Для теста Рознера достаточно дописать одну функцию, которая принимает набор данных, уровень значимости и число потенциальных выбросов:


def ESD_test(input_series, alpha, max_outliers):

    for iteration in range(max_outliers):

        Gcritical = calculate_critical_value(len(input_series), alpha)

        Gstat, max_index = grubbs_stat(input_series)

        check_G_values(Gstat, Gcritical, input_series, max_index)

        input_series = np.delete(input_series, max_index)

Используя функцию на нашем наборе данных получаем, что значение 212 является выбросом, а 44 – нет:



ESD_test(np.array(df.hwy), 0.05, 3)

Grubbs Critical Value: 3.652090929984981
Grubbs Statistics Value: 13.745808761040408
212 is an outlier
Grubbs Critical Value: 3.6508358337727187
Grubbs Statistics Value: 3.455960616168714
44 is not an outlier
Grubbs Critical Value: 3.649574509044683
Grubbs Statistics Value: 3.5561478280392245
44 is not an outlier



5182 просмотров

Добавить комментарий

[ Рекомендации ]

Читайте также

[ Дальше ]