3. 等距分箱实战:使用 pandas 的 cut 函数进行等距分箱,处理边界值与异常值
等距分箱(Equal-Width Binning)是最直观的连续变量离散化方法。它将数值范围划分为 宽度完全相等 的区间,每个区间包含的样本量可能不同。本实战将聚焦 pandas.cut 的核心用法、边界值处理策略以及异常值对分箱结果的破坏性影响。
3.1 等距分箱的核心逻辑
等距分箱的数学定义:给定特征 x 的最小值 min 与最大值 max,若分为 k 箱,则每个箱的宽度 w = (max - min) / k。分箱边界为:[min, min+w, min+2w, ..., max]。
| 特性 | 说明 |
|---|---|
| 箱宽一致 | 所有区间长度相同,便于业务解释(如年龄每10岁一组) |
| 样本分布不均 | 数据密集区箱内样本多,稀疏区可能为空箱 |
| 对异常值敏感 | 单个极大/极小值会拉伸边界,导致大部分样本挤入少数箱 |
| 边界处理 | 默认左开右闭,需关注最小值是否被包含 |
适用场景: 分布相对均匀、无极端异常值、需要固定间隔解释(如收入区间、温度区间)的特征。
3.2 pandas.cut 函数详解
cut 是 pandas 提供的等距分箱主力函数。其核心参数如下:
| 参数 | 类型 | 作用 |
|---|---|---|
x |
array-like | 待分箱的连续数据 |
bins |
int / sequence | 整数表示箱数;序列表示自定义边界 |
right |
bool | 区间是否右闭合(默认 True) |
labels |
array / False | 自定义箱标签;False 返回整数索引 |
include_lowest |
bool | 第一个区间是否包含最小值(默认 False) |
duplicates |
str | 边界重复时的处理方式('raise' / 'drop') |
3.3 基础实战:等距分箱代码
以下代码演示对模拟的“用户年龄”特征进行 5 箱等距分箱:
import pandas as pd
import numpy as np
# 生成模拟数据(含一个异常值)
np.random.seed(42)
ages = np.random.randint(18, 70, size=200)
ages = np.append(ages, [200]) # 故意加入异常值 200 岁
df = pd.DataFrame({'age': ages})
# 等距分箱:5箱
df['age_bin'] = pd.cut(df['age'], bins=5, right=True, include_lowest=True)
# 查看分箱结果分布
print(df['age_bin'].value_counts().sort_index())
输出示例(受异常值影响):
(17.7, 54.0] 152
(54.0, 90.4] 44
(90.4, 126.8] 3
(126.8, 163.2] 0
(163.2, 200.0] 1
异常值破坏性: 由于存在 200 岁的异常值,箱宽被拉伸至
(200-18)/5 ≈ 36.4,导致 18~54 岁区间挤占了 76% 的样本,而 126~163 岁区间完全为空。等距分箱对异常值极其敏感,分箱前必须做异常值截断或剔除。
3.4 边界值处理策略
等距分箱的边界值处理是实操中的关键细节,直接影响分箱的完整性与可解释性。
- 最小值包含问题: 默认
right=True且include_lowest=False时,最小值可能被排除。设置include_lowest=True确保第一个区间包含最小值。 - 边界重叠: 当数据中存在重复边界值时,设置
duplicates='drop'自动合并重复边界。 - 自定义边界: 使用
bins=[0, 20, 40, 60, 100]替代整数,可精确控制分箱节点。 - 标签映射: 使用
labels=['青年','中年','中老年','老年']提升可读性。
# 推荐做法:先截断异常值,再等距分箱
age_cap = df['age'].clip(upper=80) # 将大于80的值截断为80
df['age_bin_clean'] = pd.cut(age_cap, bins=4,
labels=['青年','中年','中老年','老年'],
include_lowest=True)
print(df['age_bin_clean'].value_counts().sort_index())
3.5 等距分箱流程与异常值处理
下图展示了从原始数据到最终分箱的完整流程,重点突出异常值检测与截断环节:
3.6 常见陷阱与避坑指南
- 空箱问题: 等距分箱后出现样本数为 0 的区间。解决方案:减少箱数或改用分位数分箱。
- 边界漂移: 训练集与测试集分别分箱导致边界不一致。解决方案:在训练集上拟合
bins,用pd.cut(test, bins=train_bins)统一映射。 - 标签顺序:
labels参数必须与bins数量一致,且按升序排列。 - 缺失值处理:
cut默认丢弃NaN,需提前填充或单独编码为“缺失”箱。
生产环境建议: 将分箱边界保存为 JSON 或 pickle 文件,在模型部署时加载同一组边界进行转换,确保线上线下一致性。
3.7 等距分箱 vs 其他分箱方法
| 分箱方法 | 箱宽 | 样本分布 | 异常值敏感度 | 业务可解释性 |
|---|---|---|---|---|
| 等距分箱 | 相等 | 不均匀 | 高 | 高(固定间隔) |
| 分位数分箱 | 不等 | 均匀 | 低 | 中(百分位) |
| 聚类分箱 | 不等 | 依聚类 | 中 | 低(需解释簇) |
| 自定义分箱 | 自定义 | 自定义 | 可控 | 最高 |