对于决策树这个经典算法,前面介绍过随机森林,今天再介绍一个它的典型升级应用,叫做GBDT,它的全称是Gradient Boosting Decision Tree,即梯度提升决策树。它的思路实则很简单,核心思想就两部分:
第一个就是Boosting机制,它会串行的训练多个精度不高的弱模型,列如前面介绍的Cart树,但是每个新模型都会纠正前面的模型的残差(残差就是实际值和预测值之间的差值)。
第二个就是梯度下降,它把优化问题转化为梯度下降的过程,对于梯度下降和偏导数这部分内容就不过多的赘述了,没接触过的朋友可以去参考高等数学的内容。
举一个具体的例子吧,列如我有一堆Cart树用于处理回归问题,第一棵树算出来的残差是50.08,那么第二棵树就只用于优化这个残差部分,假设它算出来的残差是10.44,那么第三部分就再次用来优化这部分残差,假设它算出来的新的残差是2.97,然后这样依次进行下去。由于后续的树都是用来优化前面的残差,所以整体效果不会比优化前更差,这也是“提升”二字的价值所在。
这里给一个GBDT的伪代码实现吧,如下所示:
初始化: F_0(x) = argmin_p ΣL(y_i,p)
for m in 1..M:
1. 计算伪残差: r_im = -[∂L(y_i,F(x_i))/∂F(x_i)]_{F(x)=F_{m-1}(x)}
2. 用(x_i,r_im)拟合回归树h_m(x)(叶子节点输出γ_jm)
3. 线搜索步长: ρ_m = argmin_ρ ΣL(y_i, F_{m-1}(x_i)+ρ*h_m(x_i))
4. 更新模型: F_m(x) = F_{m-1}(x) + ν*ρ_m*h_m(x) # ν是学习率
最终模型: F(x) = F_M(x)
然后来看一个具体的代码实现吧,代码如下所示:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_regression
from sklearn.metrics import mean_squared_error
# 1. 生成示例数据
X, y = make_regression(
n_samples=1000, # 样本数量
n_features=10, # 特征数量
noise=0.1, # 噪声比例
random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. 初始化GBDT模型
model = GradientBoostingRegressor(
n_estimators=200, # 树的数量
learning_rate=0.1, # 学习率
max_depth=3, # 每棵树的最大深度
validation_fraction=0.1, # 内部验证集比例
n_iter_no_change=10, # 早停轮数
tol=1e-4, # 早停阈值
random_state=42
)
# 3. 训练模型
model.fit(X_train, y_train)
# 4. 获取训练过程中的损失值
# 训练损失 (可以直接从模型获取)
train_loss = model.train_score_
# 计算验证集在每个阶段的损失
valid_loss = []
for i, y_pred in enumerate(model.staged_predict(X_valid)):
valid_loss.append(mean_squared_error(y_valid, y_pred))
# 5. 可视化损失曲线
plt.figure(figsize=(10, 6))
plt.plot(train_loss, 'b-', label='Training Loss')
plt.plot(valid_loss, 'r-', label='Validation Loss')
# 标记最佳迭代次数
best_iter = np.argmin(valid_loss)
plt.axvline(x=best_iter, color='k', linestyle='--', linewidth=1)
plt.text(best_iter+5, max(valid_loss)*0.9, f'Best Iter: {best_iter}', fontsize=12)
plt.xlabel('Boosting Iterations')
plt.ylabel('Mean Squared Error')
plt.title('Gradient Boosting Training Process')
plt.legend()
plt.grid(True)
plt.show()
# 6. 打印最佳模型信息
print(f"最佳迭代次数: {best_iter}")
print(f"训练集最终MSE: {train_loss[-1]:.4f}")
print(f"验证集最佳MSE: {min(valid_loss):.4f}")
print(f"模型实际使用的树的数量: {model.n_estimators_}")
借助sklearn这个库,我们想实现这个功能还是很简单的,我们只需要使用GradientBoostingRegressor这个类就可以了,然后就是对整体训练和验证过程的可视化,来看一下整体效果吧:

但是需要说明的是,这里我们选择了200棵树,也不是说我们无限的增加树就可以把损失值降低到无限小,这里可以看到损失也有一个极限,它不会无限减少,由于越到后面减小的越可以忽略不计了。然后看一下控制台的输出吧,如下所示:

对于更专业的列如XgBoost或者其他的Boost算法,一般都需要使用专门的类库,这里就不做演示了,推荐感兴趣的朋友们继续去深入了解,或者持续关注本系列教程。
