Pandas データビニング(cut / qcut)
データビニング(バケット分割とも呼ばれます)は、連続変数を離散化するプロセスであり、データ前処理、特徴量エンジニアリング、データ分析でよく使用されます。
cut 等幅ビニング
cutデータを等幅の区間に分割します。
サンプル
import pandas as pd
import numpy as np
# 年齢データを作成
ages = pd.Series([5, 15, 25, 35, 45, 55, 65, 75, 85])
print("元データ:")
print(ages.tolist())
print()
# 等幅ビニング(5区間)
bins = [0, 20, 40, 60, 80, 100]
labels = ["子供", "若者", "中年", "中高年", "高齢者"]
age_bins = pd.cut(ages, bins=bins, labels=labels)
print("等幅ビニング結果:")
print(age_bins)
print()
# 右境界を含む
age_bins2 = pd.cut(ages, bins=4)
print("自動等幅ビニング:")
print(age_bins2)
import numpy as np
# 年齢データを作成
ages = pd.Series([5, 15, 25, 35, 45, 55, 65, 75, 85])
print("元データ:")
print(ages.tolist())
print()
# 等幅ビニング(5区間)
bins = [0, 20, 40, 60, 80, 100]
labels = ["子供", "若者", "中年", "中高年", "高齢者"]
age_bins = pd.cut(ages, bins=bins, labels=labels)
print("等幅ビニング結果:")
print(age_bins)
print()
# 右境界を含む
age_bins2 = pd.cut(ages, bins=4)
print("自動等幅ビニング:")
print(age_bins2)
カテゴリと境界を返す
サンプル
import pandas as pd
import numpy as np
ages = pd.Series([5, 15, 25, 35, 45])
# 区間インデックスを返す
result = pd.cut(ages, bins=4, labels=False)
print("区間インデックス:")
print(result)
print()
# 区間境界を返す
result = pd.cut(ages, bins=4, retbins=True)
print("区間境界:")
print(result[1])
import numpy as np
ages = pd.Series([5, 15, 25, 35, 45])
# 区間インデックスを返す
result = pd.cut(ages, bins=4, labels=False)
print("区間インデックス:")
print(result)
print()
# 区間境界を返す
result = pd.cut(ages, bins=4, retbins=True)
print("区間境界:")
print(result[1])
qcut 等頻度ビニング
qcutデータをほぼ同じデータポイント数の区間に分割します。
サンプル
import pandas as pd
import numpy as np
# 不均一に分布したデータ
data = pd.Series([1, 1, 1, 2, 3, 4, 5, 10, 20, 30, 50, 100])
print("元データ:")
print(data.tolist())
print()
# 等幅ビニング(分布が不均一になる)
cut_result = pd.cut(data, q=4)
print("等幅ビニング:")
print(cut_result.value_counts())
print()
# 等頻度ビニング(各区間のデータポイント数がほぼ同じ)
qcut_result = pd.qcut(data, q=4)
print("等頻度ビニング:")
print(qcut_result.value_counts())
import numpy as np
# 不均一に分布したデータ
data = pd.Series([1, 1, 1, 2, 3, 4, 5, 10, 20, 30, 50, 100])
print("元データ:")
print(data.tolist())
print()
# 等幅ビニング(分布が不均一になる)
cut_result = pd.cut(data, q=4)
print("等幅ビニング:")
print(cut_result.value_counts())
print()
# 等頻度ビニング(各区間のデータポイント数がほぼ同じ)
qcut_result = pd.qcut(data, q=4)
print("等頻度ビニング:")
print(qcut_result.value_counts())
分位数を指定
サンプル
import pandas as pd
data = pd.Series(range(1, 101))
# 指定した分位数で分割
result = pd.qcut(data, q=[0, 0.1, 0.3, 0.7, 0.9, 1])
print("分位数による分割:")
print(result.value_counts().sort_index())
data = pd.Series(range(1, 101))
# 指定した分位数で分割
result = pd.qcut(data, q=[0, 0.1, 0.3, 0.7, 0.9, 1])
print("分位数による分割:")
print(result.value_counts().sort_index())
実践:データ分析
サンプル
import pandas as pd
import numpy as np
# 顧客の消費データをシミュレート
np.random.seed(42)
customers = pd.DataFrame({
"顧客ID": range(1, 101),
"消費金額": np.random.exponential(500, 100) + 100
})
# 異なる消費レベルにビニング
customers["消費レベル"] = pd.cut(
customers["消費金額"],
bins=[0, 300, 500, 800, float("inf")],
labels=["低", "中", "高", "VIP"]
)
# 各レベルの顧客数を集計
print("消費レベル分布:")
print(customers["消費レベル"].value_counts())
print()
# レベルごとに平均消費を集計
print("各レベルの平均消費:")
print(customers.groupby("消費レベル")["消費金額"].mean().round(2))
import numpy as np
# 顧客の消費データをシミュレート
np.random.seed(42)
customers = pd.DataFrame({
"顧客ID": range(1, 101),
"消費金額": np.random.exponential(500, 100) + 100
})
# 異なる消費レベルにビニング
customers["消費レベル"] = pd.cut(
customers["消費金額"],
bins=[0, 300, 500, 800, float("inf")],
labels=["低", "中", "高", "VIP"]
)
# 各レベルの顧客数を集計
print("消費レベル分布:")
print(customers["消費レベル"].value_counts())
print()
# レベルごとに平均消費を集計
print("各レベルの平均消費:")
print(customers.groupby("消費レベル")["消費金額"].mean().round(2))