【量化】从零到LGBM | 6 | LGBM代码实现和调用
LightGBM 代码实现 在上一篇文章中,我们从数学和工程设计的角度拆解了 LightGBM 的四大核心机制。本文主要来记录其代码实现。 本文分两部分回答这个问题。第一部分,我们用几百行伪代码,从零手搓一个"麻雀虽小、五脏俱全"的迷你LightGBM第二部分,我们带着手搓时拧过的每一颗"螺丝",去学习如何正确使用 LightGBM 的 Python 官方接口。 第一部分:手搓 LightGBM 0. 总体设计:先看清整张图纸 在写代码之前,我们先明确这个迷你版本要包含哪些功能,以及它们的组装顺序: EFB 特征捆绑:在数据进入模型之前,把互斥的稀疏特征合并降维(预处理阶段); 离散分箱:把连续特征值映射为整数桶编号(直方图的地基); GOSS 采样:每轮迭代时,保留大梯度样本、采样小梯度样本; 直方图构建与作差:以 $O(N)$ 的代价统计梯度信息,分裂时用减法省一半计算; Leaf-wise 生长:用优先队列实现"谁增益大谁分裂"的精英制,并用正则化参数套上缰绳; 提升主循环:每轮对"当前预测值"求一二阶导数,建一棵树,累加进模型。 这个顺序与 LightGBM 真实源码的数据流向是一致的。下面逐块实现。 1. 目标函数:先明确 $g$ 和 $h$ 从哪来 上一篇我们反复强调:一阶导 $g_i$ 和二阶导 $h_i$ 是对当前模型预测值求导的结果,下标 $i$ 表示第 $i$ 个样本。在代码里,这就是一个极其简单的函数。以平方损失 $L=\frac{1}{2}(\hat{y}_i-y_i)^2$ 为例: 1 2 3 4 5 6 7 import numpy as np def grad_hess(pred, y): """对预测值求导:g 是一阶导(误差推力),h 是二阶导(曲率)""" g = pred - y # dL/d(pred) h = np.ones_like(y) # d2L/d(pred)2,平方损失下恒为 1 return g, h 注意这个接口的通用性:如果换成分类任务,只需要把损失换成对数似然,$g$ 和 $h$ 换成对应的导数即可,后面所有的树构建代码一行都不用改。这正是 GBDT 框架"泛函梯度下降"的优雅之处——树只关心梯度,不关心具体任务。 ...