連続値を区間に分けてカテゴリ化することを「ビニング」や「階級分け」といいます。pandas の cut を使えば、数値データを簡単にグループ分けできます。
基本的な使い方
cut は値を指定した区間に分類します。
import pandas as pd df = pd.DataFrame({ 'score': [35, 55, 72, 88, 95, 45, 68] }) df['grade'] = pd.cut(df['score'], bins=[0, 40, 60, 80, 100]) print(df)
bins で境界値を指定すると、その区間ごとにデータが分類されます。結果は (0, 40]、(40, 60] のような区間のカテゴリになります。カッコの向きは「その値を含まない」、角括弧は「含む」を意味します。
ラベルを付ける
区間の表示名をカスタマイズするには labels を使います。
df['grade'] = pd.cut( df['score'], bins=[0, 40, 60, 80, 100], labels=['不可', '可', '良', '優'] ) print(df)
labels の数は bins で作られる区間の数と一致させる必要があります。区間が 4 つなら labels も 4 つです。
区間の数を自動で決める
境界値を直接指定する代わりに、分割数だけを指定することもできます。
# 4 等分する df['quartile'] = pd.cut(df['score'], bins=4)
この場合、最小値から最大値までを均等に 4 分割します。
境界値の扱いを変更する
デフォルトでは左側が開区間(含まない)、右側が閉区間(含む)です。right=False で逆にできます。
# 左を含み、右を含まない [0, 40), [40, 60), ... df['grade'] = pd.cut(df['score'], bins=[0, 40, 60, 80, 100], right=False)
また、最小値が最初の区間に含まれない問題を避けるには include_lowest=True を使います。
df['grade'] = pd.cut(df['score'], bins=[0, 40, 60, 80, 100], include_lowest=True)
qcut で分位数に基づいて分割する
qcut を使うと、データの分位数に基づいて分割できます。
# 4 分位数(四分位数)で分割 df['quartile'] = pd.qcut(df['score'], q=4)
cut は区間の幅が均等になりますが、qcut は各区間に含まれるデータ数が均等になります。
cut
指定した境界値で分割する。各区間の幅は均等だが、データ数は偏る可能性がある。
qcut
分位数で分割する。各区間のデータ数は均等だが、区間の幅は異なる。
# cut: 区間幅が均等 pd.cut(df['score'], bins=4) # qcut: データ数が均等 pd.qcut(df['score'], q=4)
実用例:年齢を年代に変換する
df = pd.DataFrame({ 'age': [23, 35, 47, 52, 18, 65, 41] }) df['age_group'] = pd.cut( df['age'], bins=[0, 20, 30, 40, 50, 60, 100], labels=['10代', '20代', '30代', '40代', '50代', '60代以上'] )
ビニングは機械学習の前処理でも頻繁に使われます。連続値をカテゴリに変換することで、モデルが学習しやすくなるケースがあります。