数值型数据:分箱#
在机器学习中,把连续的数值切成几段「桶(bucket)」再交给模型,往往比直接喂原始数值更利于建模。这一做法就叫作 分箱(binning),也常被叫作 分桶(bucketing)——它是特征工程里很常用的一招。
MLWM: 例如在机器学习第8.3.5节 特征划分中介绍决策树是如何处理连续型特怎变量时,我们就用到了类似的分箱策略。
直观地讲,分箱是把特征的不同数值子区间映射到一个个桶(bin)里,因此,在很多场景下分箱直接就把数值数据变成了类别型数据。
我们来看下面这个例子:
假设有一个名为 X 的特征,最小值是 15,最大值是 425。可以用分箱把 X 切成下面 5 个桶:
桶 1:15 到 34
桶 2:35 到 117
桶 3:118 到 279
桶 4:280 到 392
桶 5:393 到 425
桶 1 覆盖 15 到 34 这段,所以 X 在区间内的所有取值——17、29 这些——都会落进同一个桶。一个在这些桶上训练的模型,对 17 与 29 完全一视同仁,不会因为它们的具体数值有差异就给出不同的反应。
那这 5 个桶是如何进入特征向量的呢?这里就要用到一个标准的「独热(one-hot)」表示:
| 桶编号 | 范围 | 特征向量 |
|---|---|---|
| 1 | 15-34 | [1.0, 0.0, 0.0, 0.0, 0.0] |
| 2 | 35-117 | [0.0, 1.0, 0.0, 0.0, 0.0] |
| 3 | 118-279 | [0.0, 0.0, 1.0, 0.0, 0.0] |
| 4 | 280-392 | [0.0, 0.0, 0.0, 1.0, 0.0] |
| 5 | 393-425 | [0.0, 0.0, 0.0, 0.0, 1.0] |
你会发现:哪怕 X 在数据集中只占一列,在经过分箱之后,模型实际看到的却是 5 个独立特征——每个桶有自己的权重。这种「一列变多列」的切分,是分箱最关键的一点。
什么时候该用分箱#
并不是所有的特征都适合分箱,因此它是一把双刃剑。如果分箱用对了,它能显著提升模型效果;如果用错了,反而会把细节「磨平」,让模型学不到有用的模式。
当满足以下任一条件时,分箱是比缩放或裁剪更合适的替代方案:
特征与标签之间没有明显线性关系——整体呈非线性、甚至看不出相关性。
特征值在某些子区间内扎堆(即呈现「簇」状),并不均匀地铺满整个取值范围。
这听起来似乎有点反直觉,在上面这个例子中,37 和 115 明明差了好几倍,却被模型当成「同一类」。其实关键就在另一面——当特征呈现「簇状」而非「线性」时,用分箱表达数据远比直接喂原值更贴切。
下面我们通过示例来进行说明。
分箱示例:购物人数 vs 当日温度#
我们用一个具体例子把分箱的工作机制讲透。假设你在做一个模型,根据当日的室外温度预测来店的购物人数,下面这张散点图展示了温度与购物人数的关系:

从图9可以直观看出,温度最舒服的那段,购物人数最多。
那能不能直接把温度当成原值塞进模型?比如数据集里某条样本的温度是 35.0,那就用 35.0 进入特征向量——这样是不是最稳妥的做法?我们来算一笔账。
在线性回归的训练中,模型只能给每个特征学到一个全局权重。如果温度被当成单一特征,那么在预测时:35.0 对结果的影响将是 7.0 的 5 倍(或者反过来,是 1/5)。可惜从图上看,温度与标签之间没有任何明显的线性关系——硬塞线性权重反而会成为累赘。
MLWM: 上面的意思是说,温度为35°时是温度为7°时的5倍,但是35°时对应的购物任务并不是7°时的5倍,这就与 $y=wx+b$ 这个模型矛盾了。
如果改成 3 个簇,效果会好很多:
桶 1:温度区间 4 到 11。
桶 2:温度区间 12 到 26。
桶 3:温度区间 27 到 36。

切完之后,模型就能为每一桶学到独立的权重,把每段温度对购物人数的差异化影响都拾起来。
不过,桶并不是越多越好。我们来看一个反例:哪怕每个温度值单独一桶——也就是 33 个桶——通常来说都不是好主意,原因有两条:
模型只有在桶内有足够样本时,才能学到桶与标签之间的关联。 在当前例子中,每个桶都至少有 10 个样本,勉强够训练;但如果分成 33 桶,没有哪个桶能凑够训练用的样本量。
每个温度值都单独成桶,会一下子让温度特征从 1 个变成 33 个——而我们通常应该尽量减少模型里的特征数量。
小测验:检验你的理解#
下面这张图展示的是虚构国家「Freedonia」在每 0.2 度纬度上的房价中位数:

房价与纬度之间明显是非线性的关系——把纬度直接当成浮点数送进模型,恐怕帮不上什么忙。那是否应该把纬度分桶? 如果要分,最合理的策略是哪一种?
A. 不分桶
B. 分成 4 个桶
C. 把每个数据点单独成一个桶
分位数分箱#
前面说的都是「等距」分桶——把整个取值范围切成宽度相等的桶。等距分桶简单好用,但对偏态分布效果不佳,因为尾部的桶往往样本寥寥无几,模型根本学不动。
分位数分箱(quantile bucketing)正是为了补这个短板而出现的,它按样本数划分桶的边界——让每个桶里的样本数大致相等。这样一来,长尾就被压扁了。
来看一个对比。下图展示的是「等距分桶」对汽车销量的划分:每桶宽度都是 1 万美元。

可以看到:0 到 10000 这一桶塞进了几十台车,而 50000 到 60000 这一桶只有 5 台——模型在前一桶有充分样本可以学、在后一桶几乎无米下锅。
而下面这张图,用分位数分箱重新分桶,那么每个桶里的样本数大致相等,但桶的宽度差异极大。

读者可以对比一下两种切法的差异:
第 1 桶只覆盖 0 到 4000(很窄),但样本很多;
第 6 桶覆盖 25001 到 60000(特别宽),但样本数与第 1 桶相当。
分位数分箱的最大好处,是让每个桶都有足够样本去训练,从而对长尾分布也保持稳定的预测能力。
分箱策略怎么选?#
许多分布下,等距分箱都够用。但对偏态(skewed)数据,强烈推荐试试分位数分箱:
等距分箱把长尾「摊薄」成大段空白,却把高密度主体挤进了少数几个桶——尾部信号被浪费。
分位数分箱把高密度主体「摊薄」到若干个等量桶,让每个桶都有数据可学;长尾则被压进少量桶,代价是牺牲尾部细节。
关键术语:
- 分箱(Binning)
- 分桶(Bucketing)
- 裁剪(Clipping)
- 特征(Feature)
- 特征工程(Feature engineering)
- 特征向量(Feature vector)
- 标签(Label)
- 缩放(Scaling)