XGBoost决策树生成原理及举例解释
1. 决策树的基本概念
1.1 什么是决策树
决策树是一种树形结构的预测模型,它通过对数据的特征进行一系列问题(判断条件),从而得到最终的预测结果。在XGBoost中,决策树是核心组件,多棵树组合形成一个强大的集成模型。
1.2 决策树的组成部分
┌─────────────┐
│ 根节点 │ ← 树的顶部起点,包含全部样本
└──────┬──────┘
│
┌───────────┴───────────┐
│ │
┌───────▼──────┐ ┌───────▼──────┐
│ 内部节点1 │ │ 内部节点2 │ ← 表示特征测试(如x < 10)
└───────┬──────┘ └───────┬──────┘
│ │
┌───┴───┐ ┌───┴───┐
│ │ │ │
┌───▼───┐ ┌─▼─┐ ┌───▼───┐ ┌─▼─┐
│叶节点1│ │...│ │叶节点n│ │...│ ← 包含最终预测值
└───────┘ └───┘ └───────┘ └───┘
决策树主要包含三种类型的节点:
- 根节点:树的顶部起点,包含全部训练样本
- 内部节点:根节点到叶节点的中间节点,每个节点表示一个特征测试
- 叶节点:树的终端节点,包含最终的预测值
1.3 XGBoost中的决策树与传统决策树的区别
-
预测方式:
- 传统决策树:叶节点通常存储类别或平均值
- XGBoost决策树:叶节点存储连续的分数值(权重)
-
构建目标:
- 传统决策树:直接优化分类准确率或均方误差
- XGBoost决策树:优化带正则化的目标函数,基于梯度信息构建
2. XGBoost中树的生长原理
2.1 基于梯度提升的树生长
XGBoost采用梯度提升的思想,核心思路是:每一棵新树都试图拟合前面所有树的预测误差(残差)。
集成模型的预测公式:
y^i=∑k=1Kfk(xi)\hat{y}_i = \sum_{k=1}^K f_k(x_i)y^i=k=1∑Kfk(xi)
其中:
- y^i\hat{y}_iy^i 是第iii个样本的预测值
- fkf_kfk 是第kkk棵决策树模型
- KKK 是树的总数
2.2 树分裂的数学原理
在XGBoost中,树的生长由目标函数导出的最优分裂准则决定。
目标函数:
Obj=∑i=1nl(yi,y^i)+∑k=1KΩ(fk)Obj = \sum_{i=1}^n l(y_i, \hat{y}_i) + \sum_{k=1}^K \Omega(f_k)Obj=i=1∑nl(yi,y^i)+k=1∑KΩ(fk)
其中:
- l(yi,y^i)l(y_i, \hat{y}_i)l(yi,y^i) 是损失函数,衡量预测值与真实值的差距
- Ω(fk)\Omega(f_k)Ω(fk) 是正则化项,控制模型复杂度
- Ω(f)=γT+12λ∑j=1Twj2\Omega(f) = \gamma T + \frac{1}{2}\lambda\sum_{j=1}^T w_j^2Ω(f)=γT+21λ∑j=1Twj2
- TTT 是叶子节点数量
- wjw_jwj 是第jjj个叶子节点的权重
- γ\gammaγ 和 λ\lambdaλ 是正则化参数
2.3 树节点分裂的评分计算
XGBoost使用一个基于梯度的分裂评分公式来决定是否分裂节点:
Gain=12[GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ]−γGain = \frac{1}{2} \left[ \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right] - \gammaGain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ
其中:
- GLG_LGL 和 GRG_RGR 是左右子节点的一阶梯度和
- HLH_LHL 和 HRH_RHR 是左右子节点的二阶梯度和
- γ\gammaγ 是引入新叶子节点的惩罚系数
3. 第一棵树的生长过程
3.1 初始状态
在构建第一棵树之前,模型的初始预测值通常是训练数据目标变量的全局平均值或中位数。
┌────────────────────────────────────────────┐
│ │
│ 所有样本的初始预测值 = 15°C │
│ (训练数据目标变量的全局平均值) │
│ │
└────────────────────────────────────────────┘
例如,如果我们预测温度,初始预测可能是所有样本温度的平均值:y^(0)=15°C\hat{y}^{(0)} = 15°Cy^(0)=15°C
3.2 计算梯度信息
对于第一棵树,梯度信息直接基于初始预测值计算:
- 一阶梯度:gi=∂l(yi,y^i(0))∂y^i(0)g_i = \frac{\partial l(y_i, \hat{y}^{(0)}_i)}{\partial \hat{y}^{(0)}_i}gi=∂y^i(0)∂l(yi,y^i(0))
- 二阶梯度:hi=∂2l(yi,y^i(0))∂y^i(0)2h_i = \frac{\partial^2 l(y_i, \hat{y}^{(0)}_i)}{{\partial \hat{y}^{(0)}_i}^2}hi=∂y^i(0)2∂2l(yi,y^i(0))
例如,对于均方误差损失函数 l(yi,y^i)=12(yi−y^i)2l(y_i, \hat{y}_i) = \frac{1}{2}(y_i - \hat{y}_i)^2l(yi,y^i)=21(yi−y^i)2:
- 一阶梯度:gi=y^i(0)−yig_i = \hat{y}_i^{(0)} - y_igi=y^i(0)−yi
- 二阶梯度:hi=1h_i = 1hi=1
3.3 寻找最佳分裂点
XGBoost会尝试每个特征的每个可能分裂点,计算增益,并选择增益最大的分裂点。
例如,假设我们有特征"小时"(hour)和"温度滞后1"(temp_lag_1):
对特征"小时"的分裂评估:
计算特征"小时(hour)"在分裂点12的增益:
┌───────────────────────────────────┐
│ 分裂前: │
│ 所有样本 │
│ G = 0, H = 20 │
└───────────────────────────────────┘
│
▼
┌───────────────┴───────────────────┐
│ │
│ hour < 12 ? │
│ │
└───────────────┬───────────────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 左子节点: │ │ 右子节点: │
│ G_L = -50 │ │ G_R = 50 │
│ H_L = 10 │ │ H_R = 10 │
└─────────────┘ └─────────────┘
尝试分裂点 hour = 12:
- 左子节点(hour < 12):
G_L = -50, H_L = 10
- 右子节点(hour >= 12):
G_R = 50, H_R = 10
- 计算增益:
Gain = 0.5 * [((-50)²/(10+1) + (50)²/(10+1)) - (0²/(20+1))] - 0.1
Gain = 0.5 * [227.27 + 227.27 - 0] - 0.1 = 227.17
对特征"温度滞后1"的分裂评估:
计算特征"温度滞后1(temp_lag_1)"在分裂点15的增益:
┌───────────────────────────────────┐
│ 分裂前: │
│ 所有样本 │
│ G = 0, H = 20 │
└───────────────────────────────────┘
│
▼
┌───────────────┴───────────────────┐
│ │
│ temp_lag_1 < 15 ? │
│ │
└───────────────┬───────────────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 左子节点: │ │ 右子节点: │
│ G_L = 30 │ │ G_R = -30 │
│ H_L = 8 │ │ H_R = 12 │
└─────────────┘ └─────────────┘
尝试分裂点 temp_lag_1 = 15°C:
- 左子节点(temp_lag_1 < 15):
G_L = 30, H_L = 8
- 右子节点(temp_lag_1 >= 15):
G_R = -30, H_R = 12
- 计算增益:
Gain = 0.5 * [((30)²/(8+1) + (-30)²/(12+1)) - (0²/(20+1))] - 0.1
Gain = 0.5 * [100 + 69.23 - 0] - 0.1 = 84.52
由于 227.17 > 84.52,所以选择"小时"特征和分裂点12作为最佳分裂。
3.4 确定叶子节点权重
在XGBoost中,每棵决策树的叶子节点都有一个权重值,一旦决定了分裂,XGBoost会计算每个叶子节点的最优权重:
wj∗=−GjHj+λw_j^* = -\frac{G_j}{H_j + \lambda}wj∗=−Hj+λGj
- 当一个样本通过决策树的路径到达某个叶子节点时,该叶子节点的权重值就是该样本在当前树上的预测值
- XGBoost的最终预测值是多棵决策树的叶子权重之和。对于分类问题,这个和值通常会通过一个函数(如Sigmoid函数)进行转换,以得到最终的概率
- 在梯度提升框架中,每棵树的叶子权重可以被看作是对前一轮预测的“改正”,但它们本身并不是改正项,而是改正后的预测值
例如:
左叶子节点(hour < 12):
w_L = -(-50)/(10+1) = 4.55
右叶子节点(hour >= 12):
w_R = -(50)/(10+1) = -4.55
3.5 第一棵树的最终结构
┌───────────────────┐
│ 所有样本 │
│ 预测值: 15°C │
└────────┬──────────┘
│
▼
┌───────────────────┐
│ hour < 12 ? │
└────────┬──────────┘
│
┌───────────┴────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ hour < 12 │ │ hour >= 12 │
│ 预测调整: +4.55°C │ │ 预测调整: -4.55°C │
└─────────────────────┘ └─────────────────────┘
第一棵树的预测规则:
- 如果 hour < 12,预测调整值为 +4.55°C
- 如果 hour >= 12,预测调整值为 -4.55°C
4. 第二棵树的生长过程
4.1 更新预测值
第一棵树生成后,每个样本的预测值会更新:
y^i(1)=y^i(0)+η⋅f1(xi)\hat{y}_i^{(1)} = \hat{y}_i^{(0)} + \eta \cdot f_1(x_i)y^i(1)=y^i(0)+η⋅f1(xi)
其中:
- y^i(1)\hat{y}_i^{(1)}y^i(1) 是加入第一棵树后的预测值
- y^i(0)\hat{y}_i^{(0)}y^i(0) 是初始预测值
- η\etaη 是学习率(如0.1)
- f1(xi)f_1(x_i)f1(xi) 是第一棵树对样本xix_ixi的预测值
例如,对于学习率η=0.1:
- hour < 12的样本:y^i(1)=15+0.1×4.55=15.455°C\hat{y}_i^{(1)} = 15 + 0.1 \times 4.55 = 15.455°Cy^i(1)=15+0.1×4.55=15.455°C
- hour >= 12的样本:y^i(1)=15+0.1×(−4.55)=14.545°C\hat{y}_i^{(1)} = 15 + 0.1 \times (-4.55) = 14.545°Cy^i(1)=15+0.1×(−4.55)=14.545°C
4.2 计算新的梯度信息
基于更新后的预测值y^i(1)\hat{y}_i^{(1)}y^i(1),计算新的梯度:
- 一阶梯度:gi=∂l(yi,y^i(1))∂y^i(1)g_i = \frac{\partial l(y_i, \hat{y}^{(1)}_i)}{\partial \hat{y}^{(1)}_i}gi=∂y^i(1)∂l(yi,y^i(1))
- 二阶梯度:hi=∂2l(yi,y^i(1))∂y^i(1)2h_i = \frac{\partial^2 l(y_i, \hat{y}^{(1)}_i)}{{\partial \hat{y}^{(1)}_i}^2}hi=∂y^i(1)2∂2l(yi,y^i(1))
对于均方误差损失:
- 一阶梯度:gi=y^i(1)−yig_i = \hat{y}_i^{(1)} - y_igi=y^i(1)−yi
- 二阶梯度:hi=1h_i = 1hi=1
4.3 第二棵树的分裂过程
与第一棵树类似,第二棵树也通过评估所有可能的分裂来寻找最佳分裂点。不同的是,现在使用的是基于更新预测值y^i(1)\hat{y}_i^{(1)}y^i(1)计算的梯度。
第二棵树的分裂过程:
┌───────────────────────────────────┐
│ 初始状态(基于更新后的预测): │
│ 所有样本 │
│ G = 0, H = 20 │
└───────────────────────────────────┘
│
▼
┌───────────────┴───────────────────┐
│ │
│ temp_lag_1 < 15 ? │ ← 最佳分裂特征和分裂点
│ │
└───────────────┬───────────────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 左子节点: │ │ 右子节点: │
│ G_L = -28 │ │ G_R = 28 │
│ H_L = 8 │ │ H_R = 12 │
└─────────────┘ └─────────────┘
假设这次"温度滞后1"(temp_lag_1)特征的分裂得分最高:
最佳分裂特征:temp_lag_1,分裂点:15°C
左子节点(temp_lag_1 < 15):
G_L = -28, H_L = 8
w_L = -(-28)/(8+1) = 3.11
右子节点(temp_lag_1 >= 15):
G_R = 28, H_R = 12
w_R = -(28)/(12+1) = -2.15
4.4 继续分裂
XGBoost会继续评估是否应该进一步分裂这些节点。假设对于左子节点,发现使用"月份"特征进行分裂可以获得显著增益:
左子节点进一步分裂:
┌───────────────────────────────────┐
│ 左子节点(temp_lag_1 < 15): │
│ G_L = -28, H_L = 8 │
└───────────────────────────────────┘
│
▼
┌───────────────┴───────────────────┐
│ │
│ month < 6 ? │ ← 进一步分裂
│ │
└───────────────┬───────────────────┘
│
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 左-左子节点:│ │ 左-右子节点:│
│ G_LL = -20 │ │ G_LR = -8 │
│ H_LL = 4 │ │ H_LR = 4 │
└─────────────┘ └─────────────┘
左子节点进一步分裂:
特征:month,分裂点:6
左-左子节点(temp_lag_1 < 15 且 month < 6):
G_LL = -20, H_LL = 4
w_LL = -(-20)/(4+1) = 4
左-右子节点(temp_lag_1 < 15 且 month >= 6):
G_LR = -8, H_LR = 4
w_LR = -(-8)/(4+1) = 1.6
4.5 第二棵树的最终结构
┌───────────────────┐
│ 所有样本 │
└────────┬──────────┘
│
▼
┌───────────────────┐
│ temp_lag_1<15 ? │
└────────┬──────────┘
│
┌───────────┴────────────┐
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ temp_lag_1 < 15 │ │ temp_lag_1 >= 15 │
└────────┬──────────┘ │ 预测调整: -2.15°C │
│ └─────────────────────┘
│
┌────────┴──────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ month < 6 │ │ month >= 6 │
│预测调整: +4°C │ │预测调整:+1.6°C│
└───────────────┘ └───────────────┘
第二棵树的预测规则:
- 如果 temp_lag_1 < 15 且 month < 6,预测调整值为 +4.0°C
- 如果 temp_lag_1 < 15 且 month >= 6,预测调整值为 +1.6°C
- 如果 temp_lag_1 >= 15,预测调整值为 -2.15°C
4.6 更新预测值
加入第二棵树后,预测值再次更新:
y^i(2)=y^i(1)+η⋅f2(xi)\hat{y}_i^{(2)} = \hat{y}_i^{(1)} + \eta \cdot f_2(x_i)y^i(2)=y^i(1)+η⋅f2(xi)
例如,对于样本"temp_lag_1 < 15 且 month < 6":
y^i(2)=y^i(1)+0.1×4.0=15.455+0.4=15.855°C\hat{y}_i^{(2)} = \hat{y}_i^{(1)} + 0.1 \times 4.0 = 15.455 + 0.4 = 15.855°Cy^i(2)=y^i(1)+0.1×4.0=15.455+0.4=15.855°C
5. 树生长过程的直观理解
5.1 第一棵树与第二棵树的关系
┌──────────────────────┐ ┌──────────────────────┐
│ 第一棵树 │ │ 第二棵树 │
│ │ │ │
│ 捕捉昼夜温度模式 │ ────> │ 捕捉滞后和季节效应 │
│ (hour特征) │ │ (temp_lag_1和month) │
│ │ │ │
└──────────────────────┘ └──────────────────────┘
│ │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ 模型预测性能提升 │
│ │
│ - 残差逐渐减小 │
│ - 预测准确度提高 │
└──────────────────────────────┘
第一棵树捕捉数据中最明显的模式(如小时的昼夜效应),而第二棵树则专注于修正第一棵树未能捕捉的模式(如温度滞后和季节效应)。
5.2 两棵树的预测组合
┌───────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 初始预测值 │ │ 第一棵树贡献 │ │ 第二棵树贡献 │
│ 15°C │ + │ 0.455°C │ + │ 0.4°C │ = 15.855°C
└───────────────────┘ └────────────────┘ └────────────────┘
│ │ │
└─────────────────────┼────────────────────┘
│
▼
┌────────────────┐
│ 最终预测 │
│ 15.855°C │
└────────────────┘
例如,对于一个样本:
- hour < 12
- temp_lag_1 < 15
- month < 6
总预测值 = 初始预测 + 第一棵树贡献 + 第二棵树贡献
= 15°C + 0.1×4.55°C + 0.1×4.0°C
= 15°C + 0.455°C + 0.4°C
= 15.855°C
5.3 训练误差随树增加的变化
误差
│
│ ┌─── 测试误差
│ /
│ /
│ /
│ \ /
│ \ /
│ \ /
│ \ /
│ \ /
│ ─────────────────┐/
│ ─── 训练误差
│
└──────────────────────────────────────> 树的数量
第一棵树 第二棵树 过拟合点
随着树数量增加,训练误差通常会持续下降,但测试误差可能在达到某个点后开始上升(过拟合)。
6. 正则化如何影响树的生长
6.1 叶子节点复杂度惩罚 (γ)
γ参数控制新叶子生成的阈值:只有当分裂增益大于γ时,才会执行分裂。
γ值对树结构的影响:
γ = 0 (低正则化) γ = 5 (高正则化)
┌───┐ ┌───┐
│根 │ │根 │
└─┬─┘ └─┬─┘
│ │
┌───┴───┐ ┌───┴───┐
│ │ │ │
┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐
│A │ │B │ │A │ │B │
└─┬─┘ └─┬─┘ └───┘ └───┘
│ │
┌───┴───┐ │
│ │ │
│C │D │
└───┘ └───┘
- γ = 0:允许所有增益为正的分裂,树可能非常复杂
- γ = 5:只允许增益大于5的分裂,树通常更简单
6.2 叶子权重的L2正则化 (λ)
λ参数通过惩罚大的叶子权重来平滑模型预测:
wj∗=−GjHj+λw_j^* = -\frac{G_j}{H_j + \lambda}wj∗=−Hj+λGj
λ值对叶子权重的影响:
假设 G_j = -10, H_j = 2
λ = 0: w_j* = -(-10)/(2+0) = 5
λ = 1: w_j* = -(-10)/(2+1) = 3.33
λ = 10: w_j* = -(-10)/(2+10) = 0.83
λ↑ ──> 权重↓ ──> 预测更保守
- λ = 0:无正则化,权重完全由梯度决定
- λ = 10:强正则化,权重变得更小更平滑
7. 树生长的实际算法实现
XGBoost在实际实现中使用了多种优化技术来高效构建树:
7.1 精确贪婪算法
对每个可能的分裂点计算增益,选择最佳分裂点。
算法: 精确贪婪分裂
输入: 样本I, 特征集F
输出: 最佳分裂特征和分裂点
max_gain = 0
best_feature = None
best_split_point = None
对于每个特征f∈F:
对特征f按值排序
G_L = 0, H_L = 0
G_R = sum(g_i for i∈I), H_R = sum(h_i for i∈I)
对于排序后特征f的每个可能分裂点s:
将样本i从右移到左
G_L += g_i, H_L += h_i
G_R -= g_i, H_R -= h_i
gain = 计算分裂增益(G_L, H_L, G_R, H_R)
如果 gain > max_gain:
max_gain = gain
best_feature = f
best_split_point = s
返回 best_feature, best_split_point, max_gain
7.2 近似算法
对于大型数据集,XGBoost使用分位数草图或直方图来近似计算最佳分裂点。
近似算法示意:
原始特征值分布:
│ * * * * * * * * * * │
└───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┘
0 1 2 3 4 5 6 7 8 9 10
分位数近似后的候选分裂点:
│ | | | | | │
└───────┬───────┬───────┬───────┬───────┬────────┘
2 4 6 8 10
算法: 近似分裂查找
输入: 样本集I, 特征集F, 候选点数量d
输出: 最佳分裂特征和分裂点
1. 对于每个特征 f ∈ F:
1.1 构建分位数草图或直方图(d个桶)
1.2 选择d-1个候选分裂点
2. 对所有候选分裂点评估增益
3. 返回增益最大的特征和分裂点
优势:
- 大幅减少搜索空间,从O(n)降至O(d)
- d远小于n时,计算效率显著提高
7.3 缺失值处理
XGBoost能够学习缺失值的最佳处理方向:
算法: 缺失值处理
输入: 样本集I(含缺失值), 特征f, 分裂点v
输出: 缺失值的最佳方向
1. 计算两种方案:
a. 缺失值归入左子节点:
将f值缺失的样本放入左子节点
计算增益gain_left
b. 缺失值归入右子节点:
将f值缺失的样本放入右子节点
计算增益gain_right
2. 选择增益更大的方案:
如果gain_left > gain_right:
缺失值方向 = 左
否则:
缺失值方向 = 右
3. 返回最佳方向
对于每个特征的分裂,XGBoost考虑两种情况:
- 将缺失值样本分到左子节点
- 将缺失值样本分到右子节点
然后选择增益最大的方向。
8. 公式总结与直观解释
8.1 核心公式汇总
-
目标函数:
Obj=∑i=1nl(yi,y^i)+∑k=1KΩ(fk)Obj = \sum_{i=1}^n l(y_i, \hat{y}_i) + \sum_{k=1}^K \Omega(f_k)Obj=i=1∑nl(yi,y^i)+k=1∑KΩ(fk) -
正则化项:
Ω(f)=γT+12λ∑j=1Twj2\Omega(f) = \gamma T + \frac{1}{2}\lambda\sum_{j=1}^T w_j^2Ω(f)=γT+21λj=1∑Twj2 -
分裂增益:
Gain=12[GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ]−γGain = \frac{1}{2} \left[ \frac{G_L^2}{H_L + \lambda} + \frac{G_R^2}{H_R + \lambda} - \frac{(G_L + G_R)^2}{H_L + H_R + \lambda} \right] - \gammaGain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ -
叶子权重:
wj∗=−GjHj+λw_j^* = -\frac{G_j}{H_j + \lambda}wj∗=−Hj+λGj -
预测更新:
y^i(t)=y^i(t−1)+η⋅ft(xi)\hat{y}_i^{(t)} = \hat{y}_i^{(t-1)} + \eta \cdot f_t(x_i)y^i(t)=y^i(t−1)+η⋅ft(xi)
8.2 公式的直观解释
- 目标函数:在降低预测误差的同时控制模型复杂度
- 分裂增益:衡量分裂前后的损失函数改善程度减去引入新叶子的成本
- 叶子权重:梯度方向的负数,权重大小与梯度成正比,与二阶导成反比
- 预测更新:每棵新树的贡献经过学习率缩小后累加到当前预测中
9. 总结
XGBoost中树的生长是一个精心设计的过程,通过梯度信息和正则化技术来构建既准确又不过拟合的模型。每棵新树都专注于纠正前面树的错误,形成一个强大的集成模型。通过理解树的生长过程和背后的数学原理,我们可以更好地调整XGBoost模型参数,实现更好的预测性能。