Представьте: вы получили пять оценок от разных участников учебного теста. Баллы такие: 40, 10, 20, 20, 50. Задача — расставить эти значения по порядку от наименьшего к наибольшему и дать каждому участнику порядковый номер, то есть ранг. Если бы все баллы были разными, ранги просто совпали бы с номерами в отсортированном списке. Но два человека получили одинаковые 20 баллов. Как быть? Разрывать связку произвольно или назначить обоим один и тот же номер? И какой именно?

В SciPy rankdata по умолчанию используется средний ранг (метод average). Расчёт прозрачный и поддаётся проверке вручную. Разберём его по шагам на нашем примере, а потом посмотрим, чем отличаются другие соглашения.

Исходные данные

Пять наблюдений с произвольными идентификаторами:

IDБалл
U140
U210
U320
U420
U550
Учебные баллы по возрастанию: U2 10, U3 20, U4 20, U1 40, U5 50. Ранги 1, 2,5, 2,5, 4, 5: позиции 2 и 3 образуют связку.
Учебная схема, данные вымышлены. При методе среднего ранга оба значения 20 получают (2 + 3) / 2 = 2,5.

Данные вымышленные, никакого реального исследования за ними нет. Нам нужно только понять механику ранжирования.

Шаг 1. Сортировка

В этом примере выбрано возрастание: меньшему значению назначаем меньший ранг, начиная с 1. После сортировки получаем такой порядок:

  1. U2, балл 10
  2. U3, балл 20
  3. U4, балл 20
  4. U1, балл 40
  5. U5, балл 50

Двадцатки заняли вторую и третью позиции.

Шаг 2. Расчёт среднего ранга для связки

Поскольку оба балла равны, мы не можем решить, кто из них «второй», а кто «третий». Метод average предлагает компромисс: берём среднее арифметическое занятых позиций. (2 + 3) / 2 = 2,5. Этот ранг присваивается обоим участникам U3 и U4.

Шаг 3. Восстановление исходного порядка

Теперь записываем ранги напротив каждого ID в том порядке, в котором наблюдения были даны изначально:

IDБаллРанг (average)
U1404
U2101
U3202,5
U4202,5
U5505

Проверим конкретный расчёт для average: 4 + 1 + 2,5 + 2,5 + 5 = 15. До усреднения связки сумма пяти позиций равна 1 + 2 + 3 + 4 + 5 = 15. Две позиции 2 и 3 заменены двумя рангами 2,5: 2 + 3 = 2,5 + 2,5 = 5. В этом наборе сумма сохранилась. Такая проверка арифметики сама по себе не проверяет качество измерения и не доказывает правильность каждого ранга.

Чего не делает ранг

В исходных данных U1 имеет 40 баллов, а его ранг по возрастанию равен 4. У U2 — 10 баллов и ранг 1. Разность исходных баллов равна 30, а разность рангов — 3: это разные величины. Ранг 4 не означает 40% правильных ответов. Различия между уровнями измерения рассмотрены в статье о шкалах измерения.

Другие способы обработки связок

Метод average — лишь одно из соглашений. Документация SciPy rankdata (v1.18.0) перечисляет пять методов; остановимся на трёх, которые упоминаются в этом источнике.

МетодРанг для 20 (оба)Ранг для 40Ранг для 50Особенность
average2,545Позиции 2 и 3 заменены средним рангом 2,5.
min245Каждому в связке — минимальный из их номеров. Пропуск 3.
dense234Как min, но следующий ранг не пропускается.

В документации SciPy для min приведено также название competition ranking. В нашем наборе оба значения 20 получают ранг 2, а следующее значение 40 — ранг 4. При dense для того же набора ранг 40 равен 3. Это разные соглашения; выбранный способ нужно явно указать и применять последовательно.

А если ранжировать по убыванию?

Направление меняет, какое значение получает ранг 1. Если мы решим, что наибольший балл — лучший, и присвоим ему ранг 1, таблица для метода average будет выглядеть так:

IDБаллРанг (убывание, average)
U1402
U2105
U3203,5
U4203,5
U5501

Сумма снова 15. Обратите внимание: для двадцаток занятые позиции — 3 и 4, их среднее 3,5. При смене направления изменились только ранги, баллы остались прежними.

Распространённые ошибки

При выбранном average нельзя назначить двум равным значениям 20 разные ранги 2 и 3: это уже другое правило. Сумма 4 + 1 + 2 + 3 + 5 всё равно равна 15, поэтому совпадения суммы недостаточно для проверки обработки связки. Проверьте и сами значения рангов. Метод ordinal в SciPy — отдельное соглашение, его не следует незаметно подменять методом average.

Описание параметра method и разных способов обработки связок доступно в официальной документации scipy.stats.rankdata. Расчёты в этой статье выполнены отдельно для пяти вымышленных наблюдений.

В исходном примере пропусков нет. Если значение отсутствует, не подставляйте вместо него ноль: это изменит сортировку. Отдельно зафиксируйте, какие наблюдения включены в ранжирование. При использовании SciPy способ обработки NaN задаётся параметром nan_policy; здесь такой расчёт не выполняется.

Ранг описывает место значения при выбранном направлении и правиле связок; он не является процентом правильных ответов.

Как проверить себя

  1. Убедитесь, что ранги начинаются с 1, а не с 0.
  2. Для каждого значения определите его позицию в отсортированном ряду.
  3. Для каждой связки найдите занятые ею позиции и вычислите среднее (если выбран метод average).
  4. Верните ранги в исходный порядок следования ID.
  5. Для нашего примера average сверьте сумму рангов 15 с суммой позиций 1 + 2 + 3 + 4 + 5 = 15. Не переносите эту проверку суммы на min или dense: в таблице у этих методов другие значения.

Пример можно воспроизвести вручную по исходной таблице. Для обсуждения подготовки собственных данных можно обратиться за консультацией по статистическому анализу. Заранее уточните задачу и объём консультации.

Что дальше

Для описания этого примера достаточно записать: «Пять вымышленных наблюдений ранжированы по возрастанию методом среднего ранга. Одинаковым баллам 20 присвоен ранг 2,5; соответствие рангов исходным ID сохранено». Применение статистических критериев в этом примере не рассматривается.

Источники

Фото: Andy Barbour / Pexels