pandas – cut、qcut でビン分割を行う方法

目次

概要

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
  • int: x の範囲に同じ幅の bins 個のビンを定義して、ビン分割を行う。
  • sequence of scalars: この値を端点としたビンを定義して、ビン分割を行う。
  • IntervalIndex: 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 個のビンを定義して、ビン分割を行います。

In [1]:
import numpy as np
import pandas as pd

x = np.arange(10, 15)
print(x)
[10 11 12 13 14]
In [2]:
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 に数値の配列を指定した場合、この値を端点としたビンを定義して、ビン分割を行います。

In [3]:
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]]

binIntervalIndex を指定した場合、この区間をビンと定義して、ビン分割を行います。

In [4]:
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)$) となる。

In [5]:
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 の場合、その値が属するビンのインデックスを返します。

In [6]:
ret = pd.cut(x, bins=5, labels=False)
print(ret)
[0 1 2 3 4]

labels にビンの数と同じ長さの配列を指定した場合、ビンに対応するラベルを返します。

In [7]:
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 の場合はビン分割に使用したビンを一緒に返します。

In [8]:
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 の場合、最小値が含まれるように左端の区間を拡張します。

In [9]:
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. ビン分割に使用したビン

サンプルコード

In [10]:
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})]$ となります。

In [11]:
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]]
In [12]:
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 で指定します。

In [13]:
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]]

コメント

コメントする

目次