Подробные объяснения функций Pandas cut и qcut

Оглавление

Импорт библиотек и создание списка
Сведения о функции cut()
Вычисление границ функции Cut по умолчанию
value_counts()
Маркировка
Сведения о функции qcut()
ValueError: Ребра бина должны быть уникальными

Импортируйте библиотеки и создайте список

  • Сначала создайте случайный список, содержащий 20 элементов со значениями от 1 до 100.
import pandas as pd
import numpy as np
np.random.randint(100, size=(20))

  • Так как ваш случайный список будет другим, я скопировал этот список в переменную l.
l = [43, 25, 10, 92,  8, 16, 77, 32, 10, 17, 45, 92, 96, 90, 78, 66, 66, 25, 71, 71]
  • Затем давайте получим наш DataFrame и опишем его, чтобы увидеть некоторую информацию.
df = pd.DataFrame(l, columns = ['Numbers'])
df.describe()

  • Итак, у нас в списке 20 элементов.
  • Минимальное значение – 8, максимальное – 96, среднее – 51.

Описание функции cut()

  • Функция вырезания Pandas принимает в списке 2 параметра.
  • Входные данные, подобные массиву, и ячейки, которые могут быть целым числом или списком.
pd.cut(df['Numbers'], bins = 4)

  • Элемент с индексом 0 находится между 30 и 52, тогда как следующий элемент находится между 7,912 и 30.
  • Давайте посмотрим на распределение наших элементов.
pd.cut(df['Numbers'], bins = 4).value_counts()

  • Как видите, между 7,912 и 30 находится 7 элементов, а между 74 и 96 — 6 элементов.

Расчет кромки по умолчанию для функции обрезки

  • Если вы сосредоточитесь на круглых скобках, левая является исключающей, а правая — включающей.
  • Помните, что минимальное значение было 8, а максимальное — 96.
  • Поскольку наименьшие значения категорий являются исключительными, наименьшее из них должно быть меньше 8, поэтому оно равно 7,912.
  • С другой стороны, самое высокое значение равно 96, потому что самые высокие значения являются инклюзивными.
  • 96 - 8 = 88
  • 88/4 = 22. Значит, должно быть 22, интервал категорий.
  • Функция cut делает интервалы равными с этим вычислением, но это может быть изменено.
pd.cut(df['Numbers'], bins = [20,40,60,80])

  • Выше бины вводятся вручную и, как видите, первое число находится между 40 и 60.
  • Число в индексе 2 равно NaN, поскольку оно не принадлежит какому-либо определенному интервалу.
  • Имейте в виду, что все определенные интервалы находятся в диапазоне от 20 до 80, поэтому другие числа являются NaN.
pd.cut(df['Numbers'], bins = [20,40,60,80]).value_counts()

  • На выходе распределено 11 элементов, поэтому 20 – 11 = 9 элементов являются NaN.
  • Давайте включим все элементы, определив разные интервалы.
pd.cut(df['Numbers'], bins = [5,20,40,60,80,100])

  • Выше min равно 5, а max равно 100, поэтому все элементы имеют интервал.
df['Numbers'].value_counts(bins=4)

value_counts()

  • Действительно, до сих пор этот процесс можно было выполнить и с помощью функции value_counts.
  • Наблюдайте тот же результат с функцией value_counts().
df['Numbers'].value_counts(bins=4)

df['Numbers'].value_counts(bins=[20,40,60,80])

pd.cut(df['Numbers'], bins = [5,20,40,60,80,100]).value_counts()

Маркировка

  • Функция Cut также имеет функцию маркировки.
pd.cut(df['Numbers'], bins = [5,20,40,60,80,100], labels = [1,2,3,4,5])

  • Первый элемент принадлежит метке 3, второй элемент принадлежит метке 2 и так далее.
df['CutLabels'] = pd.cut(df['Numbers'], bins = [5,20,40,60,80,100], labels = [1,2,3,4,5])
df

  • Метки могут быть разными вещами, такими как символы или строки.
df['CutLabels2'] = pd.cut(df['Numbers'], bins = [5,20,40,60,80,100], labels = ['Very High','High','Medium','Low','Very Low'])
df

Детали функции qcut()

  • Вместо бинов есть параметр q для qcut.
pd.qcut(df['Numbers'], q = 4)

  • Выходные данные могут быть прочитаны как функция вырезания, так что первый элемент находится между 23 и 55.
pd.qcut(df['Numbers'], q = 4).value_counts()

  • Здесь интервалы равны не друг другу, а количеству элементов в каждой категории.
  • Вы можете увидеть эти края корзины, если вы также запустите функцию описания.
df['Numbers'].describe()

  • Имейте в виду, что это равенство справедливо только для q = 4.
  • Поскольку функция описания Pandas по умолчанию делит данные на 4 ячейки со следующими значениями квантилей: 0, 25, 50, 75 и 100.
  • Давайте определим наши собственные квантильные значения аналогично тому, что мы сделали для cut: [0,05, 0,20, 0,40, 0,60, 0,80, 1]
df['qCutLabels'] = pd.qcut(df['Numbers'], q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4,5])
df

  • Минимальное число 8 — это NaN, потому что оно ниже квантиля 0,05.
  • Давайте посмотрим ребра бина с параметром retbins.
labels, bins = pd.qcut(df['Numbers'], q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4,5], retbins = True)
bins

  • Когда мы добавляем параметр retbins, функции cut и qcut также возвращают значения края бина в качестве вывода.
  • Как вы понимаете, квантиль 0,05 соответствует значению 9,9, что означает, что наше минимальное значение 8 не находится ни в одном интервале.
  • Попробуйте сами с квантилем 0,01 и убедитесь, что он тоже больше 8.

ValueError: ребра корзины должны быть уникальными

  • Что, если квантиль 5 и квантиль 20 соответствуют одному и тому же значению?
  • Давайте добавим еще 5 восьмерок в наш фрейм данных.
l2 = [43, 25, 10, 92,  8, 16, 77, 32, 10, 17, 45, 92, 96, 90, 78, 66, 66, 25, 71, 71, 8, 8, 8, 8, 8]
df2 = pd.DataFrame(l2, columns = ['Numbers'])
df2

  • Теперь, если мы попытаемся получить бины с одинаковыми значениями квантилей, мы увидим ошибку.
df2['qCutLabels'], bins2 = pd.qcut(l2, q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4,5], retbins = True)

  • Посмотрите на нижнюю часть ошибки. Вы видите значения того, чему соответствуют наши квантили.
  • И 5, и 20 процентили равны 8.
  • Вопрос в том, где будет располагаться элемент 8. На этикетке 1 или на этикетке 2?
  • Первое решение — отказаться от одного из наших значений квантиля, которое может быть 0,05 или 0,20.
  • Прежде чем мы перейдем к решениям, давайте посмотрим, как мы можем проверить эту ситуацию, прежде чем мы увидим в ней ошибку.
for q in [0.05, 0.20, 0.40, 0.60, 0.80, 1]:
    print(q, ':', df2['Numbers'].quantile(q))

  • Вы видите, что оба квантиля 5 и 20 соответствуют 8.

Решение 1. Удаление дубликатов

df2['qCutLabels'], bins2 = pd.qcut(l2, q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4,5], retbins = True, duplicates = 'drop')

  • Мы удалили его, добавив параметр «дубликаты = ‘drop» в функцию qcut.
  • На этот раз ошибка переключилась на «Метки бина должны быть на единицу меньше, чем количество ребер бина», потому что теперь у нас 5 ребер бина.
  • Добавление еще одного края корзины или удаление этикетки решит эту проблему.
df2['qCutLabels'] = pd.qcut(l2, q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4], duplicates = 'drop')
df2

  • Я удаляю метку 5, и теперь выше результат для меток с 1 по 4.
  • Другое решение — использовать rank(method = ‘First’).

Решение № 2: rank(method='first')

  • Во-первых, давайте посмотрим, что возвращает этот метод.
df2['Numbers'].rank(method='first')

  • Как видите, он вернул еще одну серию от 1 до 25, что является количеством элементов в нашем фрейме данных.
  • Теперь все восьмерки превратились в другое число.
df2['qCutLabels2'] = df2['Numbers'].transform(lambda x: pd.qcut(x.rank(method='first'), q = [0.05, 0.20, 0.40, 0.60, 0.80, 1], labels = [1,2,3,4,5]))
df2

  • Как видите, некоторые восьмерки равны 1, некоторые — 2, а некоторые — NaN.
  • Ранги NaN 8s ниже квантиля 5, 8s с рангом метки 1 находятся между квантилем 5, а 8s с рангом метки 2 выше квантиля 5.
  • Попробуйте сами дать разные квантили.
  • В результате в первом методе все восьмерки имеют метку 1, но нам пришлось изменить наши метки или квантили. Во втором методе восьмерки распределяются по разным меткам. Итак, вы решаете, какой из них использовать в соответствии с вашей проблемой.

Запланируйте сеанс DDIChat в разделе Кодирование, программное обеспечение и разработка для мобильных устройств:



Подать заявку на участие в программе DDIChat Expert можно здесь.