W3docs

Перцентили в Python с NumPy

Как вычислять перцентили в Python с NumPy. Квартили, IQR, обнаружение выбросов, методы интерполяции и применение в ML.

Перцентиль показывает значение, ниже которого находится заданный процент наблюдений в наборе данных. Если студент набрал баллы на уровне 80-го перцентиля, значит 80 % результатов ниже его. Перцентили — краеугольный камень разведочного анализа данных; они применяются в машинном обучении для обнаружения выбросов, обрезки признаков и оценки производительности модели по подгруппам.

В этой главе рассматриваются:

  • Что такое перцентиль и как он вычисляется
  • Как использовать numpy.percentile() и numpy.quantile()
  • Квартили и пятичисловая сводка
  • Межквартильный размах (IQR) для обнаружения выбросов
  • Методы интерполяции и когда они важны
  • Нахождение ранга перцентиля конкретного значения с помощью SciPy
  • Практические сценарии ML: винсоризация и обрезка данных

Что такое перцентиль?

Перцентиль делит отсортированный набор данных на 100 равных частей. P-й перцентиль — это значение, при котором или ниже которого находится P процентов данных.

ПерцентильОбщепринятое названиеЗначение
25-йQ1 (первый квартиль)25 % значений ниже этой точки
50-йQ2 / МедианаПоловина значений ниже этой точки
75-йQ3 (третий квартиль)75 % значений ниже этой точки
90-й90 % значений ниже этой точки

Перцентили тесно связаны со средним, медианой и модой: 50-й перцентиль — это в точности медиана.

Перцентиль и квантиль

Эти термины часто используются как синонимы. Квантиль выражает ту же идею, но через дробь от 0 до 1, а не через процент от 0 до 100:

  • 25-й перцентиль = квантиль 0,25
  • 75-й перцентиль = квантиль 0,75

NumPy предоставляет как np.percentile(), так и np.quantile(). Они ведут себя одинаково; выбирайте тот вариант, который делает ваш код понятнее.

Вычисление перцентиля с помощью NumPy

numpy.percentile(a, q) принимает массив a и значение перцентиля q (0–100) и возвращает интерполированное значение в этой позиции.

Вычисление 75-го перцентиля набора данных

import numpy as np

data = [10, 20, 30, 40, 50]
result = np.percentile(data, 75)
print(result)  # Output: 40.0

Передайте список в q, чтобы вычислить несколько перцентилей за один вызов — NumPy вернёт их в виде массива:

Вычисление 25-го, 50-го и 75-го перцентилей одновременно

import numpy as np

data = [10, 20, 30, 40, 50]
p25, p50, p75 = np.percentile(data, [25, 50, 75])
print(f'Q1 = {p25}')  # Output: Q1 = 20.0
print(f'Q2 = {p50}')  # Output: Q2 = 30.0
print(f'Q3 = {p75}')  # Output: Q3 = 40.0

Использование np.quantile()

np.quantile() принимает дробь (0,0–1,0) вместо процента:

Использование np.quantile() с дробным аргументом

import numpy as np

data = [10, 20, 30, 40, 50]
q1 = np.quantile(data, 0.25)
q3 = np.quantile(data, 0.75)
print(f'Q1 = {q1}')  # Output: Q1 = 20.0
print(f'Q3 = {q3}')  # Output: Q3 = 40.0

Квартили и пятичисловая сводка

Три квартиля (Q1, Q2, Q3) вместе с минимумом и максимумом образуют пятичисловую сводку — компактный снимок разброса любого набора данных. Все пять значений можно вычислить за один вызов:

Вычисление пятичисловой сводки

import numpy as np

data = [10, 20, 30, 40, 50]
minimum, q1, median, q3, maximum = np.percentile(data, [0, 25, 50, 75, 100])

print(f'Min    = {minimum}')   # Output: Min    = 10.0
print(f'Q1     = {q1}')        # Output: Q1     = 20.0
print(f'Median = {median}')    # Output: Median = 30.0
print(f'Q3     = {q3}')        # Output: Q3     = 40.0
print(f'Max    = {maximum}')   # Output: Max    = 50.0

Пятичисловая сводка лежит в основе ящика с усами (box plot), который можно построить с помощью Matplotlib (см. Гистограммы Matplotlib для ознакомления со смежными техниками визуализации).

Межквартильный размах и обнаружение выбросов

Межквартильный размах (IQR) — это расстояние между Q1 и Q3:

IQR = Q3 − Q1

Он описывает разброс средних 50 % данных. Поскольку IQR игнорирует верхний и нижний кварталы, он устойчив к экстремальным значениям — что делает его стандартным инструментом для правило-основанного обнаружения выбросов.

Правило заборов Тьюки помечает любое значение, выходящее за пределы 1,5 × IQR от любого из квартилей, как потенциальный выброс:

  • Нижняя граница: Q1 − 1,5 × IQR
  • Верхняя граница: Q3 + 1,5 × IQR

Обнаружение выбросов методом IQR

import numpy as np

data = [5, 7, 8, 9, 10, 11, 12, 13, 14, 80]

q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1

lower_fence = q1 - 1.5 * iqr
upper_fence = q3 + 1.5 * iqr

outliers = [x for x in data if x < lower_fence or x > upper_fence]

print(f'Q1 = {q1}, Q3 = {q3}, IQR = {iqr}')
# Output: Q1 = 8.25, Q3 = 12.75, IQR = 4.5

print(f'Lower fence = {lower_fence}, Upper fence = {upper_fence}')
# Output: Lower fence = 1.5, Upper fence = 19.5

print(f'Outliers: {outliers}')
# Output: Outliers: [80]

Значение 80 значительно превышает верхнюю границу 19,5, поэтому оно помечается как выброс. Метод IQR широко используется, поскольку не требует никаких предположений о лежащем в основе распределении данных.

Методы интерполяции

Когда запрашиваемый перцентиль попадает между двумя точками данных, NumPy применяет интерполяцию. Параметр method (добавлен в NumPy 1.22 на замену устаревшему параметру interpolation) определяет способ вычисления.

Сравнение методов интерполяции на 35-м перцентиле

import numpy as np

data = [10, 20, 30, 40, 50]
# The 35th percentile falls between 20 (index 1) and 30 (index 2)

print(np.percentile(data, 35, method='linear'))    # Output: 24.0  (default)
print(np.percentile(data, 35, method='lower'))     # Output: 20
print(np.percentile(data, 35, method='higher'))    # Output: 30
print(np.percentile(data, 35, method='midpoint'))  # Output: 25.0
print(np.percentile(data, 35, method='nearest'))   # Output: 20
МетодОписаниеКогда использовать
linearВзвешенное среднее двух соседних значенийПо умолчанию; наиболее статистически корректный
lowerВозвращает меньшее из двух соседних значенийКогда необходимы целочисленные индексы
higherВозвращает большее из двух соседних значенийКонсервативные верхние границы
midpointСреднее из меньшего и большегоПростые отчёты о среднем диапазоне
nearestБлижайшая реальная точка данныхКогда результат должен быть реальным наблюдением

Для большинства задач анализа данных и ML метод linear по умолчанию является правильным выбором.

Нахождение перцентильного ранга значения

Иногда возникает обратная задача: для заданного значения определить его перцентиль. Используйте scipy.stats.percentileofscore():

Определение перцентильного ранга конкретного значения

from scipy import stats

data = [10, 20, 30, 40, 50]

rank = stats.percentileofscore(data, 30)
print(rank)  # Output: 60.0

rank_of_25 = stats.percentileofscore(data, 25)
print(rank_of_25)  # Output: 40.0

Значение 30 находится на 60-м перцентиле — это означает, что 60 % значений в data равны 30 или меньше его.

Практическое применение в ML: винсоризация

Винсоризация (также называемая обрезкой) ограничивает экстремальные значения на выбранной перцентильной границе вместо их удаления. Это сохраняет количество строк, одновременно ограничивая влияние выбросов на обучение модели.

Обрезка выбросов до диапазона 10-го–90-го перцентилей

import numpy as np

data = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200]

lower = np.percentile(data, 10)
upper = np.percentile(data, 90)

clipped = np.clip(data, lower, upper)

print(f'Lower bound (10th): {lower}')  # Output: Lower bound (10th): 20.0
print(f'Upper bound (90th): {upper}')  # Output: Upper bound (90th): 100.0
print('Clipped:', list(clipped))
# Output: Clipped: [20.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 100.0]

Оба экстремальных значения — 10 (ниже нижней перцентильной границы 20) и 200 (выше верхней перцентильной границы 100) — ограничиваются граничным значением. Винсоризация — распространённый шаг предобработки перед обучением линейных моделей или нейронных сетей, особенно на финансовых данных или данных с датчиков, где экстремальные показания встречаются часто.

Подробнее о подходах к масштабированию признаков, дополняющих обрезку на основе перцентилей, читайте в главе Масштабирование.

Краткий справочник

ЗадачаФункцияПример
Один перцентильnp.percentile(data, q)np.percentile(data, 75)
Несколько перцентилейnp.percentile(data, [q1, q2, …])np.percentile(data, [25, 50, 75])
Квантиль (шкала 0–1)np.quantile(data, q)np.quantile(data, 0.75)
Пятичисловая сводкаnp.percentile(data, [0,25,50,75,100])
IQRQ3 − Q1np.percentile(data, 75) - np.percentile(data, 25)
Перцентильный ранг значенияscipy.stats.percentileofscore(data, v)
Обрезка до границ перцентиляnp.clip(data, lower, upper)np.clip(data, p10, p90)

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

Заключение

Перцентили ранжируют значения внутри набора данных и раскрывают его форму так, как не могут ни среднее, ни стандартное отклонение. С помощью numpy.percentile() вычисление Q1, Q2, Q3 и IQR занимает всего одну строку Python. В машинном обучении перцентили применяются на каждом этапе: в разведочном анализе данных для выявления выбросов, в предобработке для винсоризации экстремальных значений и при оценке для понимания точности модели на всём распределении данных. Владение ими даёт надёжный инструмент без предположений о распределении, который работает с любым набором данных.

Was this page helpful?