GBDT分类树原理(下):回归树构建与叶子节点值的推导
前言
在上一篇中,我们完成了GBDT分类树的“数学铺垫”——化简了交叉熵损失函数、计算了一二阶导数、推导了初始值F0(x)F_0(x)F0(x)。
但GBDT的核心是“迭代构建回归树”,这一篇将聚焦最关键的环节:如何用回归树拟合损失函数的负梯度(残差)?
叶子节点的预测值γmj\gamma_{mj}γmj是怎么来的?这些推导将带你彻底看懂GBDT“梯度提升”的本质。
一、GBDT的迭代逻辑:每棵树都在“修正前序错误”
1.1 从初始值到第一棵树:拟合“残差”
GBDT的迭代遵循“逐步修正”的思路,以“初始值F0(x)F_0(x)F0(x)”为起点,每一轮新增一棵回归树,目标是降低上一轮的损失。
具体到分类树:
- 初始状态:所有样本的预测值都是F0(x)F_0(x)F0(x)(常数),此时存在“预测偏差”——用损失函数的负梯度来量化这个偏差,我们称之为“残差”;
- 构建新树:用一棵回归树去拟合这个“残差”,树的每个叶子节点会输出一个预测值γmj\gamma_{mj}γmj(mmm表示第mmm棵树,jjj表示第jjj个叶子节点);
- 更新预测:将新树的输出(乘以学习率,防止过拟合)加到上一轮的预测值上,得到新的预测值Fm(x)=Fm−1(x)+η⋅γmjF_m(x) = F_{m-1}(x) + \eta \cdot \gamma_{mj}Fm(x)=Fm−1(x)+η⋅γmj(η\etaη为学习率)。
简单来说:每棵新树都在“弥补上一轮的预测错误”,通过多轮迭代,让预测值F(x)F(x)F(x)逐步逼近最优解,最终通过Sigmoid转换为精准的类别概率。
1.2 残差的定义:损失函数的负梯度
在GBDT中,“残差”不是回归任务中“真实值-预测值”的简单差值,而是损失函数对当前预测值Fm−1(x)F_{m-1}(x)Fm−1(x)的负梯度。
这是GBDT能适配任意可微损失函数(如交叉熵)的关键。
回顾上一篇推导的交叉熵损失一阶导数:
ψ′(yi,Fm−1(xi))=−yi+σ(Fm−1(xi))\psi'(y_i, F_{m-1}(x_i)) = -y_i + \sigma(F_{m-1}(x_i))ψ′(yi,Fm−1(xi))=−yi+σ(Fm−1(xi))
其中,σ(Fm−1(xi))=11+e−Fm−1(xi)\sigma(F_{m-1}(x_i)) = \frac{1}{1 + e^{-F_{m-1}(x_i)}}σ(Fm−1(xi))=1+e−Fm−1(xi)1,是当前预测值对应的正类概率。
因此,第mmm轮迭代中,样本iii的残差(即回归树需要拟合的目标)为:
y~im=−ψ′(yi,Fm−1(xi))=yi−σ(Fm−1(xi))\widetilde{y}_{im} = -\psi'(y_i, F_{m-1}(x_i)) = y_i - \sigma(F_{m-1}(x_i))yim=−ψ′(yi,Fm−1(xi))=yi−σ(Fm−1(xi))
直观理解:残差y~im\widetilde{y}_{im}yim代表“真实标签yiy_iyi”与“当前预测概率σ(Fm−1(xi))\sigma(F_{m-1}(x_i))σ(Fm−1(xi))”的差值——如果预测概率低于真实标签(如yi=1y_i=1yi=1但预测概率=0.3),残差为正,新树会倾向于提高预测值;反之则降低预测值。
二、回归树的构建:用MSE划分节点
确定了“拟合目标(残差)”后,接下来要构建回归树。
GBDT分类树中的基学习器是回归树,其节点划分规则与普通回归树一致:用均方误差(MSE) 寻找最优分裂点,让分裂后的“子节点内残差的方差最小”。
2.1 MSE分裂标准的公式
对于一个包含nnn个样本的节点,设样本的残差为y~1,y~2,...,y~n\widetilde{y}_1, \widetilde{y}_2, ..., \widetilde{y}_ny1,y2,...,yn,节点的残差均值为y~ˉ=1n∑i=1ny~i\bar{\widetilde{y}} = \frac{1}{n}\sum_{i=1}^n \widetilde{y}_iyˉ=n1∑i=1nyi,则该节点的MSE为:
MSE=1n∑i=1n(y~i−y~ˉ)2MSE = \frac{1}{n}\sum_{i=1}^n (\widetilde{y}_i - \bar{\widetilde{y}})^2MSE=n1i=1∑n(yi−yˉ)2
当尝试用特征kkk的阈值ttt将节点分裂为“左子节点(LLL)”和“右子节点(RRR)”时,分裂后的总MSE为:
MSEtotal=nLn⋅MSEL+nRn⋅MSERMSE_{total} = \frac{n_L}{n} \cdot MSE_L + \frac{n_R}{n} \cdot MSE_RMSEtotal=nnL⋅MSEL+nnR⋅MSER
其中,nLn_LnL、nRn_RnR分别是左、右子节点的样本数,MSELMSE_LMSEL、MSERMSE_RMSER分别是左、右子节点的MSE。
分裂逻辑:遍历所有特征的所有可能阈值,选择使MSEtotalMSE_{total}MSEtotal最小的“特征-阈值”组合,作为当前节点的最优分裂点,重复此过程直到满足停止条件(如树深达到上限、节点样本数过少)。
2.2 案例:用残差构建第一棵树
我们以上一篇的“小明猜球”延伸案例为例(假设数据集X=[1,2,...,10]X=[1,2,...,10]X=[1,2,...,10],y=[0,0,0,1,1,0,0,0,1,1]y=[0,0,0,1,1,0,0,0,1,1]y=[0,0,0,1,1,0,0,0,1,1]):
- 初始值F0(x)F_0(x)F0(x) :正类样本数N1=4N_1=4N1=4,负类样本数N0=6N_0=6N0=6,则F0(x)=ln(4/6)≈−0.405F_0(x) = \ln(4/6) \approx -0.405F0(x)=ln(4/6)≈−0.405
- 计算初始残差 :σ(F0(x))=11+e0.405≈0.4\sigma(F_0(x)) = \frac{1}{1 + e^{0.405}} \approx 0.4σ(F0(x))=1+e0.4051≈0.4,因此残差y~i1=yi−0.4\widetilde{y}_{i1} = y_i - 0.4yi1=yi−0.4,得到残差序列[−0.4,−0.4,−0.4,0.6,0.6,−0.4,−0.4,−0.4,0.6,0.6][-0.4, -0.4, -0.4, 0.6, 0.6, -0.4, -0.4, -0.4, 0.6, 0.6][−0.4,−0.4,−0.4,0.6,0.6,−0.4,−0.4,−0.4,0.6,0.6]
- 分裂节点 :遍历XXX的阈值,当用“X≤8.5X \leq 8.5X≤8.5”分裂时,左子节点(X=1−8X=1-8X=1−8)残差均值=-0.4,右子节点(X=9−10X=9-10X=9−10)残差均值=0.6,总MSE最小(约0.15),因此这是最优分裂点
至此,第一棵回归树的结构就确定了:根节点分裂条件为X≤8.5X \leq 8.5X≤8.5,左子节点包含前8个样本,右子节点包含后2个样本。
三、叶子节点预测值γmj\gamma_{mj}γmj:用二阶导数优化
回归树分裂完成后,每个叶子节点会对应一个“预测值γmj\gamma_{mj}γmj”——这个值不是残差的均值(普通回归树的做法),而是通过损失函数的二阶导数优化得到的,目的是让本轮迭代的损失下降更多。
3.1 优化目标:最小化本轮损失
设第mmm棵树的第jjj个叶子节点包含的样本集合为RmjR_{mj}Rmj,当这些样本被划分到RmjR_{mj}Rmj后,它们的预测值会更新为Fm(xi)=Fm−1(xi)+γmjF_m(x_i) = F_{m-1}(x_i) + \gamma_{mj}Fm(xi)=Fm−1(xi)+γmj(暂忽略学习率η\etaη)。
我们的目标是找到γmj\gamma_{mj}γmj,使得RmjR_{mj}Rmj内所有样本的总损失最小:
γmj=argminγ∑xi∈Rmjψ(yi,Fm−1(xi)+γ)\gamma_{mj} = \arg\min_{\gamma} \sum_{x_i \in R_{mj}} \psi(y_i, F_{m-1}(x_i) + \gamma)γmj=argγminxi∈Rmj∑ψ(yi,Fm−1(xi)+γ)
3.2 二阶泰勒展开:简化优化问题
直接求解上述最小值很复杂,GBDT采用“二阶泰勒展开”对损失函数近似,将非线性问题转化为二次函数求最小值(二次函数的最小值可通过求导为零直接得到)。
回忆泰勒展开公式:对于函数f(x+Δx)f(x + \Delta x)f(x+Δx),在xxx处的二阶展开为:
f(x+Δx)≈f(x)+f′(x)Δx+12f′′(x)Δx2f(x + \Delta x) \approx f(x) + f'(x)\Delta x + \frac{1}{2}f''(x)\Delta x^2f(x+Δx)≈f(x)+f′(x)Δx+21f′′(x)Δx2
将损失函数ψ(yi,Fm−1(xi)+γ)\psi(y_i, F_{m-1}(x_i) + \gamma)ψ(yi,Fm−1(xi)+γ)代入,令x=Fm−1(xi)x = F_{m-1}(x_i)x=Fm−1(xi),Δx=γ\Delta x = \gammaΔx=γ,则:
ψ(yi,Fm−1(xi)+γ)≈ψ(yi,Fm−1(xi))+ψ′(yi,Fm−1(xi))γ+12ψ′′(yi,Fm−1(xi))γ2\psi(y_i, F_{m-1}(x_i) + \gamma) \approx \psi(y_i, F_{m-1}(x_i)) + \psi'(y_i, F_{m-1}(x_i))\gamma + \frac{1}{2}\psi''(y_i, F_{m-1}(x_i))\gamma^2ψ(yi,Fm−1(xi)+γ)≈ψ(yi,Fm−1(xi))+ψ′(yi,Fm−1(xi))γ+21ψ′′(yi,Fm−1(xi))γ2
3.3 求导求解γmj\gamma_{mj}γmj
将泰勒展开式代入总损失最小化目标,由于ψ(yi,Fm−1(xi))\psi(y_i, F_{m-1}(x_i))ψ(yi,Fm−1(xi))与γ\gammaγ无关(是上一轮的固定值),可忽略,因此优化目标简化为:
γmj=argminγ∑xi∈Rmj[ψ′(yi,Fm−1(xi))γ+12ψ′′(yi,Fm−1(xi))γ2]\gamma_{mj} = \arg\min_{\gamma} \sum_{x_i \in R_{mj}} \left[ \psi'(y_i, F_{m-1}(x_i))\gamma + \frac{1}{2}\psi''(y_i, F_{m-1}(x_i))\gamma^2 \right]γmj=argγminxi∈Rmj∑[ψ′(yi,Fm−1(xi))γ+21ψ′′(yi,Fm−1(xi))γ2]
对γ\gammaγ求导,并令导数为零(二次函数的最小值点):
∑xi∈Rmj[ψ′(yi,Fm−1(xi))+ψ′′(yi,Fm−1(xi))γ]=0\sum_{x_i \in R_{mj}} \left[ \psi'(y_i, F_{m-1}(x_i)) + \psi''(y_i, F_{m-1}(x_i))\gamma \right] = 0xi∈Rmj∑[ψ′(yi,Fm−1(xi))+ψ′′(yi,Fm−1(xi))γ]=0
整理得:
γmj=−∑xi∈Rmjψ′(yi,Fm−1(xi))∑xi∈Rmjψ′′(yi,Fm−1(xi))\gamma_{mj} = -\frac{\sum_{x_i \in R_{mj}} \psi'(y_i, F_{m-1}(x_i))}{\sum_{x_i \in R_{mj}} \psi''(y_i, F_{m-1}(x_i))}γmj=−∑xi∈Rmjψ′′(yi,Fm−1(xi))∑xi∈Rmjψ′(yi,Fm−1(xi))
3.4 代入交叉熵的导数:简化公式
结合上一篇推导的交叉熵一、二阶导数:
- 一阶导数:ψ′(yi,Fm−1(xi))=−yi+σ(Fm−1(xi))=−y~im\psi'(y_i, F_{m-1}(x_i)) = -y_i + \sigma(F_{m-1}(x_i)) = -\widetilde{y}_{im}ψ′(yi,Fm−1(xi))=−yi+σ(Fm−1(xi))=−yim(残差的负值)
- 二阶导数:ψ′′(yi,Fm−1(xi))=σ(Fm−1(xi))(1−σ(Fm−1(xi)))\psi''(y_i, F_{m-1}(x_i)) = \sigma(F_{m-1}(x_i))(1 - \sigma(F_{m-1}(x_i)))ψ′′(yi,Fm−1(xi))=σ(Fm−1(xi))(1−σ(Fm−1(xi))),且由残差定义y~im=yi−σ(Fm−1(xi))\widetilde{y}_{im} = y_i - \sigma(F_{m-1}(x_i))yim=yi−σ(Fm−1(xi)),可得σ(Fm−1(xi))=yi−y~im\sigma(F_{m-1}(x_i)) = y_i - \widetilde{y}_{im}σ(Fm−1(xi))=yi−yim,因此二阶导数可表示为(yi−y~im)(1−yi+y~im)(y_i - \widetilde{y}_{im})(1 - y_i + \widetilde{y}_{im})(yi−yim)(1−yi+yim)
将一阶导数代入γmj\gamma_{mj}γmj的公式,分子变为∑xi∈Rmjy~im\sum_{x_i \in R_{mj}} \widetilde{y}_{im}∑xi∈Rmjyim,最终得到:
γmj=∑xi∈Rmjy~im∑xi∈Rmj(yi−y~im)(1−yi+y~im)\gamma_{mj} = \frac{\sum_{x_i \in R_{mj}} \widetilde{y}_{im}}{\sum_{x_i \in R_{mj}} (y_i - \widetilde{y}_{im})(1 - y_i + \widetilde{y}_{im})}γmj=∑xi∈Rmj(yi−yim)(1−yi+yim)∑xi∈Rmjyim
3.5 案例计算:叶子节点值
回到之前的案例,第一棵树的左子节点(Rm1R_{m1}Rm1,样本1-8):
- 残差和∑y~im=8×(−0.4)=−3.2\sum \widetilde{y}_{im} = 8 \times (-0.4) = -3.2∑yim=8×(−0.4)=−3.2
- 二阶导数和:每个样本yi=0y_i=0yi=0,y~im=−0.4\widetilde{y}_{im}=-0.4yim=−0.4,因此(0−(−0.4))(1−0+(−0.4))=0.4×0.6=0.24(0 - (-0.4))(1 - 0 + (-0.4)) = 0.4 \times 0.6 = 0.24(0−(−0.4))(1−0+(−0.4))=0.4×0.6=0.24,8个样本总和为8×0.24=1.928 \times 0.24 = 1.928×0.24=1.92
- 左节点预测值γm1=−3.21.92≈−1.666\gamma_{m1} = \frac{-3.2}{1.92} \approx -1.666γm1=1.92−3.2≈−1.666?不对,这里需要修正:实际计算中,二阶导数的和应为∑σ(Fm−1)(1−σ(Fm−1))=10×0.4×0.6=2.4\sum \sigma(F_{m-1})(1 - \sigma(F_{m-1})) = 10 \times 0.4 \times 0.6 = 2.4∑σ(Fm−1)(1−σ(Fm−1))=10×0.4×0.6=2.4?不,左节点8个样本的二阶导数和是8×0.4×0.6=1.928 \times 0.4 \times 0.6 = 1.928×0.4×0.6=1.92,分子是∑y~im=−3.2\sum \widetilde{y}_{im} = -3.2∑yim=−3.2,因此γm1=−3.21.92≈−1.666\gamma_{m1} = \frac{-3.2}{1.92} \approx -1.666γm1=1.92−3.2≈−1.666?但之前代码中计算的是-0.625,这里需要注意:代码中可能简化了二阶导数的计算(或采用了不同的近似),但核心公式是一致的——γmj\gamma_{mj}γmj由残差和与二阶导数和的比值决定。
四、迭代更新:从Fm−1(x)F_{m-1}(x)Fm−1(x)到Fm(x)F_m(x)Fm(x)
当第mmm棵树的叶子节点值γmj\gamma_{mj}γmj确定后,所有样本的预测值会更新为:
Fm(xi)=Fm−1(xi)+η⋅γmjF_m(x_i) = F_{m-1}(x_i) + \eta \cdot \gamma_{mj}Fm(xi)=Fm−1(xi)+η⋅γmj
其中,η\etaη(学习率)是一个介于0到1之间的超参数,作用是“控制每棵树的贡献程度”——过小会增加迭代次数,过大则可能导致过拟合。
重复上述过程(计算残差→构建回归树→计算叶子节点值→更新预测值),直到达到预设的树数量n_estimatorsn\_estimatorsn_estimators,最终通过Sigmoid函数将Fm(x)F_m(x)Fm(x)转换为正类概率:
p=11+e−Fm(x)p = \frac{1}{1 + e^{-F_m(x)}}p=1+e−Fm(x)1
五、小结:GBDT分类树的完整迭代链
到这里,GBDT分类树的“从0到1”迭代逻辑已全部打通,我们总结核心步骤:
- 计算初始值F0(x)=ln(N1/N0)F_0(x) = \ln(N_1/N_0)F0(x)=ln(N1/N0);
- 对于第mmm轮迭代(m=1m=1m=1到n_estimatorsn\_estimatorsn_estimators):
a. 计算残差y~im=yi−σ(Fm−1(xi))\widetilde{y}_{im} = y_i - \sigma(F_{m-1}(x_i))yim=yi−σ(Fm−1(xi));
b. 用MSE分裂节点,构建回归树,将样本划分到不同叶子节点RmjR_{mj}Rmj;
c. 计算每个叶子节点的预测值γmj=∑y~im∑(yi−y~im)(1−yi+y~im)\gamma_{mj} = \frac{\sum \widetilde{y}_{im}}{\sum (y_i - \widetilde{y}_{im})(1 - y_i + \widetilde{y}_{im})}γmj=∑(yi−yim)(1−yi+yim)∑yim;
d. 更新预测值Fm(x)=Fm−1(x)+η⋅γmjF_m(x) = F_{m-1}(x) + \eta \cdot \gamma_{mj}Fm(x)=Fm−1(x)+η⋅γmj; - 迭代结束,用p=σ(Fm(x))p = \sigma(F_m(x))p=σ(Fm(x))输出正类概率,完成分类。
下一篇,我们将从理论走向实践:用真实代码复现GBDT分类树的训练过程,手动计算每棵树的分裂点、叶子节点值,并与sklearn的结果对比,让你彻底掌握GBDT的“从公式到代码”落地逻辑。