概要
pandas の cut、qcut でビン分割を行う方法を解説します。
ビン分割
ビン分割 (binning) とは、ビン (bins) と呼ばれる互いに重複しない区間を用意し、数値をその値が属するビンに割り振ることをいいます。
pandas.cut
pandas.cut() は、与えられた数値配列をビン分割する関数です。
pandas.cut(x, bins, right: = True, labels=None, retbins: = False, precision: = 3, include_lowest: = False, duplicates: = 'raise')
名前 | 型 | デフォルト値 |
---|---|---|
x | array-like | |
ビン分割する1次元の入力配列。 | ||
bins | int, sequence of scalars, or IntervalIndex | |
|
||
right | bool | True |
ビンの区間は right=True の場合は右半開区間、right=False の場合は左半開区間になる。bins が IntervalIndex の場合はこの引数は無視される。 | ||
labels | array or False | None |
labels=False の場合は値が属するビンのインデックスを返す。 labels にビンの数と同じ長さの配列を指定した場合、ビンに対応するラベルを返す。 labels=True の場合、例外が送出される。 |
||
retbins | bool | False |
retbins=True の場合はビン分割に使用したビンを一緒に返す。 | ||
precision | int | 3 |
ビンを表示する際の精度 | ||
include_lowest | bool | False |
include_lowest=True かつ right=False の場合は x の最小値を含むように最初のビンの区間の左端を1%だけ拡張する。 include_lowest=True かつ right=True の場合は x の最大値を含むように最後のビンの区間の右端を1%だけ拡張する。 |
||
duplicates | {default ‘raise’, ‘drop’}, optional | |
ビンの区間に重複が含まれる場合の挙動を制御する。 |
名前 | 説明 |
---|---|
Categorical, Series, or ndarray | x の各要素が属するビン |
numpy.ndarray or IntervalIndex. | ビン分割に使用したビン |
bin – ビンを指定する
bin
に int を指定した場合、x
の範囲に同じ幅の bins
個のビンを定義して、ビン分割を行います。
import numpy as np
import pandas as pd
x = np.arange(10, 15)
print(x)
[10 11 12 13 14]
ret, bins = pd.cut(x, bins=5, retbins=True)
print(ret)
print(bins)
[(9.996, 10.8], (10.8, 11.6], (11.6, 12.4], (12.4, 13.2], (13.2, 14.0]] Categories (5, interval[float64]): [(9.996, 10.8] < (10.8, 11.6] < (11.6, 12.4] < (12.4, 13.2] < (13.2, 14.0]] [ 9.996 10.8 11.6 12.4 13.2 14. ]
bin
に数値の配列を指定した場合、この値を端点としたビンを定義して、ビン分割を行います。
bins = [0, 20, 40, 60, 100]
print(bins)
ret = pd.cut(x, bins)
print(ret)
[0, 20, 40, 60, 100] [(0, 20], (0, 20], (0, 20], (0, 20], (0, 20]] Categories (4, interval[int64]): [(0, 20] < (20, 40] < (40, 60] < (60, 100]]
bin
に IntervalIndex
を指定した場合、この区間をビンと定義して、ビン分割を行います。
bins = pd.interval_range(0, 100, 5)
print(bins)
ret = pd.cut(x, bins)
print(ret)
IntervalIndex([(0, 20], (20, 40], (40, 60], (60, 80], (80, 100]], closed='right', dtype='interval[int64]') [(0, 20], (0, 20], (0, 20], (0, 20], (0, 20]] Categories (5, interval[int64]): [(0, 20] < (20, 40] < (40, 60] < (60, 80] < (80, 100]]
right – ビンの区間を右半開区間にするかどうか
right=True
の場合、各ビンは右半開区間 (例: $(0, 20]$) となります。right=False
の場合、各ビンは左半開区間 (例: $[0, 20)$) となる。
ret = pd.cut(x, bins=4, right=True)
print("right=True", ret.categories, sep="\n")
ret = pd.cut(x, bins=4, right=False)
print("right=False", ret.categories, sep="\n")
right=True IntervalIndex([(9.996, 11.0], (11.0, 12.0], (12.0, 13.0], (13.0, 14.0]], closed='right', dtype='interval[float64]') right=False IntervalIndex([[10.0, 11.0), [11.0, 12.0), [12.0, 13.0), [13.0, 14.004)], closed='left', dtype='interval[float64]')
labels – ビンのインデックスまたはラベルを返すようにする
labels=False
の場合、その値が属するビンのインデックスを返します。
ret = pd.cut(x, bins=5, labels=False)
print(ret)
[0 1 2 3 4]
labels にビンの数と同じ長さの配列を指定した場合、ビンに対応するラベルを返します。
ret = pd.cut(x, bins=3, labels=["bad", "medium", "good"])
print(ret)
[bad, bad, medium, good, good] Categories (3, object): [bad < medium < good]
retbins – ビンを返り値として一緒に返すかどうか
retbins=True
の場合はビン分割に使用したビンを一緒に返します。
ret, bins = pd.cut(x, bins=5, retbins=True)
print(bins)
[ 9.996 10.8 11.6 12.4 13.2 14. ]
include_lowest – 最初(最後)の区間の端を拡張するかどうか
bins に1次元配列または IntervalIndex を指定した場合で include_lowest=True の場合、最小値が含まれるように左端の区間を拡張します。
bins = pd.cut(x, bins=[0, 20, 40, 60, 100], include_lowest=False)
print(bins.categories)
bins = pd.cut(x, bins=[0, 20, 40, 60, 100], include_lowest=True)
print(bins.categories)
IntervalIndex([(0, 20], (20, 40], (40, 60], (60, 100]], closed='right', dtype='interval[int64]') IntervalIndex([(-0.001, 20.0], (20.0, 40.0], (40.0, 60.0], (60.0, 100.0]], closed='right', dtype='interval[float64]')
pandas.qcut
pandas.qcut は、分位数に基づいたビン分割を行います。
pandas.qcut(x, q, labels=None, retbins: = False, precision: = 3, duplicates: = 'raise')
名前 | 型 | デフォルト値 |
---|---|---|
x | 1d ndarray or Series | ビン分割する1次元の配列 |
q | int or list-like of float | |
分位数の数、または分位数の一覧を指定する。 | ||
labels | array or False | None |
labels=False の場合は値が属するビンのインデックスを返す。 labels にビンの数と同じ長さの配列を指定した場合、ビンに対応するラベルを返す。 labels=True の場合、例外が送出される。 |
||
retbins | bool, optional | |
retbins=True の場合はビン分割に使用したビンを一緒に返す。 | ||
precision | int, optional | |
ビンを表示する際の精度 | ||
duplicates | {default ‘raise’, ‘drop’}, optional | |
ビンの区間に重複が含まれる場合の挙動を制御する。 |
名前 | 説明 |
---|---|
Categorical, Series, or ndarray | x の各要素が属するビン |
numpy.ndarray or IntervalIndex. | ビン分割に使用したビン |
サンプルコード
import numpy as np
import pandas as pd
x = np.array(
[30, 6, 10, 7, 33, 8, 17, 12, 1, 38, 28, 27, 47, 10, 23, 10, 30, 30, 41, 3, 50]
)
print(x.min(), x.max())
1 50
q
に int を指定した場合、まず $[0, 100]$ を等間隔に q
分割して、分位数 $q_1, q_2, \cdots, q_{n + 1}$ を作成します。
そして、ビンの区間は $(Q(q_0), Q(q_1)], (Q(q_1), Q(q_2)], \cdots, (Q(q_n), Q(q_{n + 1})]$ となります。
ret = pd.qcut(x, q=4)
print(ret)
[(23.0, 30.0], (0.999, 10.0], (0.999, 10.0], (0.999, 10.0], (30.0, 50.0], ..., (23.0, 30.0], (23.0, 30.0], (30.0, 50.0], (0.999, 10.0], (30.0, 50.0]] Length: 21 Categories (4, interval[float64]): [(0.999, 10.0] < (10.0, 23.0] < (23.0, 30.0] < (30.0, 50.0]]
qs = np.linspace(0, 100, 5) # q=4 の場合
print(qs)
bins = np.percentile(x, qs)
print(bins)
[ 0. 25. 50. 75. 100.] [ 1. 10. 23. 30. 50.]
$q = [q_1, q_2, \cdots, q_{n + 1}]$ とした場合、ビンの区間は $(Q(q_0), Q(q_1)], (Q(q_1), Q(q_2)], \cdots, (Q(q_n), Q(q_{n + 1})]$ となります。分位数は $[0, 1]$ の float で指定します。
ret = pd.qcut(x, q=[0, 0.25, 0.5, 0.75, 1])
print(ret)
[(23.0, 30.0], (0.999, 10.0], (0.999, 10.0], (0.999, 10.0], (30.0, 50.0], ..., (23.0, 30.0], (23.0, 30.0], (30.0, 50.0], (0.999, 10.0], (30.0, 50.0]] Length: 21 Categories (4, interval[float64]): [(0.999, 10.0] < (10.0, 23.0] < (23.0, 30.0] < (30.0, 50.0]]
コメント