17370845950

如何自定义分箱区间并确保右端点闭合(如 [190, 200])

本文介绍在 pandas 中实现非标准分箱(尤其是让最后一个区间为闭区间 `[190, 200]`)的实用方法:先用 `pd.cut(..., right=false)` 构建左闭右开基础分箱,再通过布尔掩码将精确等于 200 的值强制归入目标闭区间。

在数据预处理中,分箱(binning)是常见操作,但 pd.cut 默认仅支持统一的开闭性(全部左闭右开或左开右闭),无法直接定义混合边界——例如前四个区间为左闭右开 [a, b),而最后一个区间需为左闭右闭 [190, 200]。此时,单纯调整 right 参数无法满足需求,需结合后处理实现精准控制。

核心思路是:分两步走

  1. 使用 pd.cut(..., right=False) 按左闭右开规则划分所有区间(包括 [190, 200));
  2. 单独识别值恰好等于 200 的样本,并用 .mask() 将其对应分箱标签替换为 '[190, 200]'。

以下为完整可运行示例:

import pandas as pd

# 构造测试数据:100.0 到 200.3,步长 0.1(含精确的 200.0)
s = pd.Series(range(1000, 2004)).div(10)  # 100.0, 100.1, ..., 200.0, 200.1, ...

# 定义分箱边界(5个区间 → 6个端点)
bins = [100, 135, 160, 175, 190, 200]
labels = ['[100, 135)', '[135, 160)', '[160, 175)', '[175, 190)', '[190, 200]']

# 第一步:标准左闭右开分箱(此时 200 落入 NaN,因超出 [190, 200))
cut_result = pd.cut(s, bins=bins, labels=labels, right=False)

# 第二步:定位值为 200 的位置,并覆盖标签
cond = s == 200.0

out = cut_result.mask(cond, '[190, 200]') print(out.iloc[998:1003]) # 查看关键片段

输出中可见:

  • 199.9 → [190, 200](原属 [190, 200),被 pd.cut 正确分配)
  • 200.0 → [190, 200](经 .mask() 强制修正)
  • 200.1 及以上 → NaN(超出最大边界,符合预期)

⚠️ 注意事项:

  • 若数据中存在大于 200 的值(如示例中的 200.1),它们将默认返回 NaN,可根据业务需要额外处理(如追加 include_lowest=True 或扩展 bins);
  • labels 长度必须比 bins 少 1,否则报错;
  • 使用 mask() 时确保条件向量 cond 与 cut_result 索引对齐(本例中天然一致);
  • 若需保留数值型结果而非字符串标签,可改用 pd.cut(..., retbins=False) + 自定义 pd.IntervalIndex 映射,但复杂度显著上升——对多数场景,布尔掩码法更简洁可靠。

该方案兼顾准确性与可读性,是处理“混合区间闭合性”问题的推荐实践。