Skip to content

LightGBM 如何用直方图生长一棵树 ​

上一节已经知道怎样评价一刀。现在的问题是:样本和特征很多时,如何更便宜地枚举候选,又该先切哪片叶子?

本页固定 LightGBM 4.6.0 的 CPU、普通 GBDT、常数叶。沿用四行数据和初始梯度 [1,1,-1,-1],关注样本统计如何流入一次分裂。

1. 从原始数值到 bin ​

手写树对原始不同值逐个枚举阈值。直方图算法先把数值映射到有限的箱,也就是 bin。箱边界通常在训练数据构建阶段形成,之后树学习复用它们;并非每轮都用标签重新分箱。

为了手算,先假设四个不同数值各占一箱:

bin原始 x数量 N梯度和 GHessian 和 H
01111
12111
231-11
341-11

这是一张特征直方图,不是标签频率图。每个节点、每个被考虑的特征,要汇总该节点样本的梯度统计。本页 N 是教学用的显式计数;库内部不同目标和实现分支可能利用 Hessian 估计数量。

扫描到 bin 1 之后,左侧前缀和是 GL=2,HL=2;从父统计 G=0,H=4 中减去左侧,就得 GR=−2,HR=2。代入上一页的公式即可评价阈值 2.5。

2. 分箱节省了哪部分工作 ​

构建一列直方图仍要处理节点样本,大致是 O(n);建好后扫描候选只需 O(B),B 是箱数。它没有让读取训练数据变成零成本。官方 Features 说明了分箱与直方图差分的基本机制。

压缩也会失去候选。假如把 x=2 和 x=3 合并到一箱,原本的 2.5 就不再是箱间边界。这是速度、内存与切分精细程度之间的取舍,不是箱数越大必然泛化越好。

max_bin 是上限,不保证实际生成这么多箱。样本值分布、分箱最小样本要求和缺失处理也会影响可用边界。

3. 子节点直方图还能相减 ​

父节点已经有直方图,分裂后只为一个孩子从样本重建统计,另一个可以通过:

Histright=Histparent−Histleft

逐箱得到。通常选择样本较少的孩子构建,减少扫描。这个等式依赖三者使用相同分箱定义,并且两个孩子恰好把父节点样本分完。

检查点:上表父节点每箱 H=1。如果左孩子只包含 x=1、2,左直方图 H 为 [1,1,0,0],相减得到右侧 [0,0,1,1]。负计数或不守恒的梯度和都应触发排查。

4. 叶子优先回答另一个问题 ​

“在哪个阈值切”与“下一次切哪个叶子”是两个层次。LightGBM 的叶子优先生长会为可切叶子维护最佳候选,然后选择增益最大的那个继续分裂。

text
当前叶子 A:最佳合法增益 0.8
当前叶子 B:最佳合法增益 2.1  ← 下一次选择
当前叶子 C:没有合法正增益   ← 保持叶子

这里是说明调度的独立数值示意,不是四行数据的第三轮输出。四行例子在一刀后已没有进一步正增益。

逐层生长按深度推进;叶子优先允许在某一侧长出更深路径。num_leaves 限制叶子数,max_depth 限制路径深度,二者不能互相替代。设置深度上限不会把 LightGBM 改成逐层生长。参数配合可参照 官方调参指南。

5. 缺失值也必须有路由 ​

本章手写树拒绝 NaN;LightGBM 可以处理缺失。训练在合法候选中考虑缺失的归属,保存预测时采用的默认方向。

4.6.0 默认使用 NaN 表示缺失,zero_as_missing=false,因此数值 0 通常仍是观测值。只有确认 0 的数据语义就是缺失时,才考虑改变该设置。稀疏矩阵中未存储的位置在默认配置下也按零处理。见 缺失值说明。

“可以路由缺失”不说明缺失机制合理。例如训练数据中的缺失来自某个流程,未来流程改变,模型仍可能失效。它解决输入如何通过树,不自动解决数据来源问题。

6. 类别编码不是连续大小 ​

类别 A、B、C 编码为 0、1、2,若当作普通数值,阈值只能按编码大小切分。声明为类别特征后,算法可以考虑类别集合的划分;高基数情形使用梯度统计排序等策略,小类别数也有相应分支。

在本版接口中应显式指定 categorical_feature,采用稳定的非负整数编码;负值被视为缺失。训练和预测必须保持同一映射,否则同一个整数就会代表不同对象。见 类别特征说明。

7. 进阶:GOSS 与 EFB 放在哪里 ​

它们解决规模问题,主线不要求先实现:

  • GOSS 调整用于估计分裂统计的样本:保留大梯度样本,对小梯度部分采样并修正权重。
  • EFB 利用稀疏特征很少同时非零的结构进行打包,减少有效特征处理量。

这是 LightGBM 原论文 的主要主题。本版普通训练并不默认开启 GOSS;具体开关查本章速查页。不要把“论文提出某机制”理解为“所有训练都必经这个机制”。

小结、自测与下一步 ​

  1. 为什么直方图相减必须共用分箱边界?
  2. 合并 x=2、3 的箱会丢掉哪个候选?
  3. 为什么 max_depth=3 不等于一定生成 8 个叶子?
参考答案
  1. 相减的每个位置必须描述同一个原始值区间,否则统计没有可比意义。
  2. 2.5,原本完美区分标签的一刀可能消失。
  3. 8 只是深度 3 二叉树的叶子上限;样本约束、增益和叶子预算都会让实际树更小。

下一步:训练、早停与重载一个 LightGBM 模型。

最近更新