Коротко
pd.cut(s, bins=[…])— по заданным границам;bins=3— на 3 интервала одинаковой ширины.- Интервалы по умолчанию
(a, b]: правая граница входит, левая нет.right=False—[a, b). labels=[…]— свои названия групп вместо интервалов.pd.qcut(s, q=4)— по квантилям: в каждой группе примерно одинаковое число значений.- Результат — категориальный Series с упорядоченными категориями; значения вне интервалов —
NaN.
Синтаксис
pd.cut(s, bins, right=True, labels=None, include_lowest=False)
pd.qcut(s, q, labels=None, duplicates="raise")
pd.qcut(s, q, retbins=True) # вернуть и границыПараметры
ПараметрЧто делаетПо умолчанию
binsв cut: список границ или число интервалов равной шириныобязательныйqв qcut: число групп или список квантилей [0, 0.25, …, 1]обязательныйrightв cut: правая граница входит в интервалTruelabelsназвания групп; False — номера группNoneinclude_lowestв cut: включить левую границу первого интервалаFalseduplicatesв qcut: "drop" — убрать совпадающие границы вместо ошибки"raise"Примеры
ages = pd.Series([17, 23, 35, 41, 18, 52, 67, 29, 30, 45], name="age")pd.cut(ages, bins=[0, 18, 30, 50, 100]) # интервалы (a, b]: правая граница входитВывод
0 (0, 18] 1 (18, 30] 2 (30, 50] 3 (30, 50] 4 (0, 18] 5 (50, 100] 6 (50, 100] 7 (18, 30] 8 (18, 30] 9 (30, 50] Name: age, dtype: category Categories (4, interval[int64, right]): [(0, 18] < (18, 30] < (30, 50] < (50, 100]]
groups = pd.cut(ages, bins=[0, 18, 30, 50, 100], labels=["до 18", "18–30", "30–50", "50+"])
groups.value_counts(sort=False)Вывод
age до 18 2 18–30 3 30–50 3 50+ 2 Name: count, dtype: int64
pd.cut(ages, bins=[0, 18, 30, 50, 100], right=False).value_counts(sort=False) # [a, b)Вывод
age [0, 18) 1 [18, 30) 3 [30, 50) 4 [50, 100) 2 Name: count, dtype: int64
pd.cut(ages, bins=3) # 3 интервала одинаковой шириныВывод
0 (16.95, 33.667] 1 (16.95, 33.667] 2 (33.667, 50.333] 3 (33.667, 50.333] 4 (16.95, 33.667] 5 (50.333, 67.0] 6 (50.333, 67.0] 7 (16.95, 33.667] 8 (16.95, 33.667] 9 (33.667, 50.333] Name: age, dtype: category Categories (3, interval[float64, right]): [(16.95, 33.667] < (33.667, 50.333] < (50.333, 67.0]]
pd.qcut(ages, q=4, labels=["Q1", "Q2", "Q3", "Q4"]).value_counts(sort=False) # примерно поровну в каждойВывод
age Q1 3 Q2 2 Q3 2 Q4 3 Name: count, dtype: int64
edges = pd.qcut(ages, q=4, retbins=True)[1]
edges # границы квартилейВывод
array([17. , 24.5, 32.5, 44. , 67. ])
Подводные камни
Значения вне интервалов
Всё, что не попало ни в один интервал, — в том числе значение, равное левой границе первого интервала, — становится NaN. Проверяйте isna().sum() после cut или используйте include_lowest=True.
pd.cut(pd.Series([5, 150]), bins=[0, 18, 100]) # значение вне интервалов → NaNВывод
0 (0.0, 18.0] 1 NaN dtype: category Categories (2, interval[int64, right]): [(0, 18] < (18, 100]]
Много одинаковых значений в qcut
pd.qcut(pd.Series([1, 1, 1, 1, 2, 3]), q=4) # границы квантилей совпадаютОшибка
ValueError: Bin edges must be unique: Index([1.0, 1.0, 1.0, 1.75, 3.0], dtype='float64'). You can drop duplicate edges by setting the 'duplicates' kwarg
Передайте duplicates="drop" — групп станет меньше — или используйте rank(method="first") перед qcut.