### XGBoost单棵树类
class XGBoost_Single_Tree(BinaryDecisionTree):# 结点分裂方法def node_split(self, y):# 中间特征所在列feature = int(np.shape(y)[1]/2)# 左子树为真实值,右子树为预测值y_true, y_pred = y[:, :feature], y[:, feature:]return y_true, y_pred# 信息增益计算方法def gain(self, y, y_pred):# 梯度计算Gradient = np.power((y * self.loss.gradient(y, y_pred)).sum(), 2)# Hessian矩阵计算Hessian = self.loss.hess(y, y_pred).sum()return 0.5 * (Gradient / Hessian)# 树分裂增益计算# 式(12.28)def gain_xgb(self, y, y1, y2):# 结点分裂y_true, y_pred = self.node_split(y)y1, y1_pred = self.node_split(y1)y2, y2_pred = self.node_split(y2)true_gain = self.gain(y1, y1_pred)false_gain = self.gain(y2, y2_pred)gain = self.gain(y_true, y_pred)return true_gain + false_gain - gain# 计算叶子结点最优权重def leaf_weight(self, y):y_true, y_pred = self.node_split(y)# 梯度计算gradient = np.sum(y_true * self.loss.gradient(y_true, y_pred), axis=0)# hessian矩阵计算hessian = np.sum(self.loss.hess(y_true, y_pred), axis=0)# 叶子结点得分leaf_weight = gradient / hessianreturn leaf_weight# 树拟合方法def fit(self, X, y):self.impurity_calculation = self.gain_xgbself._leaf_value_calculation = self.leaf_weightsuper(XGBoost_Single_Tree, self).fit(X, y)
这段代码定义了一个基于 XGBoost 的单棵决策树类,扩展自 BinaryDecisionTree
,用于实现梯度提升树的部分功能。以下是对代码的详细解读,包括其核心函数和算法设计思想。
代码结构分析
1. node_split(self, y)
功能:
- 将输入数据
y
分为真实值 y true y_{\text{true}} ytrue 和预测值 y pred y_{\text{pred}} ypred,便于计算梯度和 Hessian。
实现:
- y y y 被假定为一个二维数组,其中前半部分是真实值,后半部分是预测值。
- 使用切片操作将 y y y 拆分为 y true y_{\text{true}} ytrue 和 y pred y_{\text{pred}} ypred。
feature = int(np.shape(y)[1] / 2)
y_true, y_pred = y[:, :feature], y[:, feature:]
2. gain(self, y, y_pred)
功能:
- 计算节点的损失函数增益(单节点增益),公式为:
Gain = 1 2 ( ∑ Gradient ) 2 Hessian \text{Gain} = \frac{1}{2} \frac{\left( \sum \text{Gradient} \right)^2}{\text{Hessian}} Gain=21Hessian(∑Gradient)2
实现:
- 梯度计算: ( y ∗ gradient ) . sum() (y * \text{gradient}).\text{sum()} (y∗gradient).sum() 计算所有样本的梯度总和,然后取平方。
- Hessian 计算: hessian . sum() \text{hessian}.\text{sum()} hessian.sum() 求二阶导数的总和。
- 增益公式:结合梯度平方和 Hessian 求增益。
Gradient = np.power((y * self.loss.gradient(y, y_pred)).sum(), 2)
Hessian = self.loss.hess(y, y_pred).sum()
return 0.5 * (Gradient / Hessian)
3. gain_xgb(self, y, y1, y2)
功能:
- 计算节点分裂前后的总增益,公式为:
Gain Split = Gain Left + Gain Right − Gain Parent \text{Gain}_{\text{Split}} = \text{Gain}_{\text{Left}} + \text{Gain}_{\text{Right}} - \text{Gain}_{\text{Parent}} GainSplit=GainLeft+GainRight−GainParent
实现:
- 分裂节点:调用
node_split
将 y , y 1 , y 2 y, y_1, y_2 y,y1,y2 分别拆分为真实值和预测值。 - 左右子节点增益:分别计算 Gain Left \text{Gain}_{\text{Left}} GainLeft 和 Gain Right \text{Gain}_{\text{Right}} GainRight。
- 父节点增益:计算分裂前的增益 Gain Parent \text{Gain}_{\text{Parent}} GainParent。
- 总增益:将左右子节点增益之和减去父节点增益。
y_true, y_pred = self.node_split(y)
y1, y1_pred = self.node_split(y1)
y2, y2_pred = self.node_split(y2)
true_gain = self.gain(y1, y1_pred)
false_gain = self.gain(y2, y2_pred)
gain = self.gain(y_true, y_pred)
return true_gain + false_gain - gain
4. leaf_weight(self, y)
功能:
- 计算叶子节点的最优权重,用于更新叶子节点的预测值,公式为:
w ∗ = ∑ Gradient ∑ Hessian w^* = \frac{\sum \text{Gradient}}{\sum \text{Hessian}} w∗=∑Hessian∑Gradient
实现:
- 梯度计算:计算真实值 y true y_{\text{true}} ytrue 和预测值 y pred y_{\text{pred}} ypred 的梯度和。
- Hessian 计算:计算真实值和预测值的二阶导数和。
- 权重计算:直接使用公式 w ∗ = Gradient Hessian w^* = \frac{\text{Gradient}}{\text{Hessian}} w∗=HessianGradient。
gradient = np.sum(y_true * self.loss.gradient(y_true, y_pred), axis=0)
hessian = np.sum(self.loss.hess(y_true, y_pred), axis=0)
leaf_weight = gradient / hessian
return leaf_weight
5. fit(self, X, y)
功能:
- 训练决策树,设置增益计算方法和叶子节点权重计算方法。
实现:
- 将
gain_xgb
设置为 impurity 计算方法,用于指导树的分裂。 - 将
leaf_weight
设置为叶子节点的值计算方法。 - 调用父类
BinaryDecisionTree
的fit
方法,完成树的训练。
self.impurity_calculation = self.gain_xgb
self._leaf_value_calculation = self.leaf_weight
super(XGBoost_Single_Tree, self).fit(X, y)
整体流程
-
数据拆分:
- 使用
node_split
方法将数据拆分为真实值和预测值部分。
- 使用
-
节点增益计算:
- 使用
gain
方法计算单节点的增益。 - 使用
gain_xgb
方法计算分裂前后的增益。
- 使用
-
叶子节点权重计算:
- 使用
leaf_weight
方法计算叶子节点的最优预测值。
- 使用
-
树的训练:
- 通过
fit
方法调用父类的逻辑,完成树的构建。
- 通过
与 XGBoost 的公式对比
代码中的实现与 XGBoost 中的增益公式略有不同:
-
增益公式的差异:
- 当前实现的增益公式是简化的,缺少正则化参数 λ \lambda λ 和分裂成本 γ \gamma γ。
- 完整的 XGBoost 增益公式为:
Gain = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ \text{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] - \gamma Gain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ - 当前实现适合快速计算增益,但与 XGBoost 的公式不完全一致。
-
正则化的实现:
- 当前实现未引入正则化参数 λ \lambda λ 和 γ \gamma γ,这可能会导致树结构过于复杂或分裂无效。
- 在实际 XGBoost 应用中,正则化项能够有效控制模型复杂度,提升泛化能力。
总结
这段代码实现了 XGBoost 单棵决策树的基础功能,包括节点增益计算、叶子节点权重更新和树的训练逻辑。尽管实现有所简化,但它为构建完整的 XGBoost 算法提供了一个良好的基础。