超全面讲透一个算法模型,GBDT!!

文摘   2024-10-16 17:36   北京  

大家好~

今天和大家再来聊聊GBDT,好的模型总是需要反复的思考。

确实在这些提升树方面的模型,大家总是有问不完的问题、讨论不晚的知识点。

GBDT,全名是梯度提升决策树(Gradient Boosting Decision Tree),是一种常用的机器学习算法。我们可以把它分成两部分来理解:决策树梯度提升

1. 决策树(Decision Tree)——“做选择”

你可以把决策树想象成一种根据问题做选择的“问答游戏”。举个例子:

假设你想判断今天要不要带伞,我们可以用一个决策树来帮忙:

第一个问题:今天会下雨吗?

  • 如果是:带伞。
  • 如果不是:第二个问题,今天多云吗?
    • 如果是:带伞。
    • 如果不是:不带伞。

这个过程就像是根据一个一个条件做出判断,最后得到一个明确的结论。这就是决策树的基本思想:每一步根据某个特征的值进行判断,直到得到最终结果

2. 梯度提升(Boosting)——“不断改进”

梯度提升的意思是,通过多个弱模型(比如多个小决策树)的叠加,不断改进预测的准确性。也就是说,我们不是一次就建一个完美的决策树,而是先建一个不太完美的决策树,然后逐步改进。

举个小例子:

假设我们想预测房子的价格,最开始我们建了一个简单的决策树模型,它的预测结果可能不够准确,有些房子价格偏高,有些偏低。接下来,我们就根据这个初始模型犯的“错误”来建第二棵树,让第二棵树专门修正第一棵树的错误。这样,不断地修正,最终的模型会越来越准确。

这个“不断修正”的过程,就是梯度提升的思想。每一步都在改进之前的预测结果,直到整个模型变得非常准确。

3. 那么 GBDT 是怎么工作的?

GBDT的工作流程可以简单理解为:

  1. 第一步:先建一个简单的决策树模型,用它做初步预测,比如预测房价。
  2. 第二步:计算这个模型预测的误差,看看哪些房子预测错了(比如价格太高或太低)。
  3. 第三步:基于这些误差,建第二棵决策树,让它专门修正这些错误。
  4. 重复上述步骤:不断重复这个过程,每次都用新的决策树来修正上一个模型的错误。
  5. 最终结果:所有这些决策树的预测结果加起来,就是最终的预测结果。

4. 举例子说明

假设我们在预测某个城市的房价,初始模型预测:

  • 房子A的实际价格是300万,模型预测300万,没错!
  • 房子B的实际价格是500万,但模型只预测了450万,偏低了50万。
  • 房子C的实际价格是700万,但模型预测了800万,偏高了100万。

于是,我们根据这些预测误差(50万和100万),让第二棵决策树专门来修正它们。第二棵树可能会说:“房子B要再加50万,房子C要减100万。” 这样,总的预测结果会更加接近真实价格。

最终,GBDT 通过一次次的改进,逐渐提升模型的预测准确性。

总结来看,GBDT 是一种通过多个小决策树合作工作不断改进预测结果的机器学习算法。它非常强大,特别是在处理一些复杂问题时,比如预测房价、用户行为等等。

在上面的简单解释的基础上,我们从原理和案例和大家好好聊聊,现在可以很好的接受了~

基础原理

GBDT 公式推导

1. 目标函数

GBDT 的目标是通过多个决策树模型来最小化预测误差,假设我们有一个训练数据集 ,目标是构建一个函数  来预测 

每一步  的目标是使得损失函数  最小化:

其中, 是损失函数,通常选择均方误差(MSE):

2. 梯度提升

GBDT 的思想是用一个初始模型  开始,然后逐步修正预测误差。每一步我们需要拟合一个新模型来修正之前模型的残差。为了实现这一点,我们使用梯度下降法。

在第  步时,我们想找到一个新的模型  来修正前一轮的预测误差。于是,我们有:

其中, 是一个学习率系数, 是第  棵新树,它拟合的是损失函数对模型的梯度,即:

通过最小化这个梯度,我们可以不断更新模型,最终得到一个高精度的预测函数。

案例实现

接下来我将基于上述推导,在 Python 中手动实现 GBDT~

1. 数据集准备

我们构造一个虚拟的回归数据集,包含两个特征和一个目标变量,假设数据符合某个非线性关系。

import numpy as np
import matplotlib.pyplot as plt

# 生成虚拟数据集
np.random.seed(42)
n_samples = 1000
X = np.random.uniform(01, (n_samples, 2))
y = 4 * X[:, 0] + 2 * np.sin(5 * X[:, 1]) + np.random.normal(00.1, n_samples)

# 将数据可视化
plt.figure(figsize=(86))
plt.scatter(X[:, 0], y, color='red', label='Feature 1 vs Target', alpha=0.7)
plt.scatter(X[:, 1], y, color='blue', label='Feature 2 vs Target', alpha=0.7)
plt.title("Feature vs Target Plot")
plt.xlabel("Feature Value")
plt.ylabel("Target Value")
plt.legend()
plt.show()

2. 手动实现 GBDT 算法

以下是实现一个简化的 GBDT 模型代码,该代码将基于决策树残差拟合多次迭代:

from sklearn.tree import DecisionTreeRegressor

class GradientBoostingRegressor:
    def __init__(self, n_estimators=100, learning_rate=0.1, max_depth=3):
        self.n_estimators = n_estimators
        self.learning_rate = learning_rate
        self.max_depth = max_depth
        self.models = []
        self.gammas = []
    
    def fit(self, X, y):
        # 初始化模型 F_0(x)
        F_0 = np.mean(y)
        self.models.append(F_0)
        F_t = np.full_like(y, F_0)
        
        for i in range(self.n_estimators):
            # 计算残差 r_t = y - F_t(x)
            residual = y - F_t
            
            # 拟合残差的回归树 h_t(x)
            tree = DecisionTreeRegressor(max_depth=self.max_depth)
            tree.fit(X, residual)
            
            # 预测新树的输出
            h_t = tree.predict(X)
            
            # 更新模型 F_{t+1}(x) = F_t(x) + γ * h_t(x)
            gamma = self.learning_rate
            F_t += gamma * h_t
            
            # 保存模型
            self.models.append(tree)
            self.gammas.append(gamma)
    
    def predict(self, X):
        # 使用所有的树进行预测
        F_t = np.full(X.shape[0], self.models[0])
        for tree, gamma in zip(self.models[1:], self.gammas):
            F_t += gamma * tree.predict(X)
        return F_t

3. 训练模型并可视化

我们使用上面构建的虚拟数据集来训练这个 GBDT 模型,并可视化结果。

# 训练 GBDT 模型
gbdt = GradientBoostingRegressor(n_estimators=10, learning_rate=0.1, max_depth=3)
gbdt.fit(X, y)

# 预测结果
y_pred = gbdt.predict(X)

# 可视化拟合效果
plt.figure(figsize=(86))
plt.scatter(X[:, 0], y, color='red', label='Actual', alpha=0.7)
plt.scatter(X[:, 0], y_pred, color='green', label='Predicted', alpha=0.7)
plt.title("Actual vs Predicted Values (Feature 1)")
plt.xlabel("Feature 1")
plt.ylabel("Target Value")
plt.legend()
plt.show()

plt.figure(figsize=(86))
plt.scatter(X[:, 1], y, color='blue', label='Actual', alpha=0.7)
plt.scatter(X[:, 1], y_pred, color='orange', label='Predicted', alpha=0.7)
plt.title("Actual vs Predicted Values (Feature 2)")
plt.xlabel("Feature 2")
plt.ylabel("Target Value")
plt.legend()
plt.show()

# 可视化残差
residuals = y - y_pred
plt.figure(figsize=(86))
plt.scatter(y_pred, residuals, color='purple', alpha=0.7)
plt.axhline(y=0, color='black', linestyle='--')
plt.title("Residuals vs Predicted")
plt.xlabel("Predicted Values")
plt.ylabel("Residuals")
plt.show()

# 可视化损失变化
train_loss = []
F_0 = np.mean(y)
F_t = np.full_like(y, F_0)
for i, (tree, gamma) in enumerate(zip(gbdt.models[1:], gbdt.gammas)):
    F_t += gamma * tree.predict(X)
    loss = np.mean((y - F_t) ** 2)
    train_loss.append(loss)

plt.figure(figsize=(86))
plt.plot(range(len(train_loss)), train_loss, marker='o', color='blue')
plt.title("Training Loss Over Iterations")
plt.xlabel("Iteration")
plt.ylabel("MSE Loss")
plt.show()

Feature vs Target Plot:展示了两个特征与目标值的关系,可以看到特征与目标值之间的某种非线性关系。

Actual vs Predicted (Feature 1) Actual vs Predicted (Feature 2):这些图展示了模型预测结果与实际值的对比,观察拟合的效果。

Residuals vs Predicted:残差图展示了预测值与残差之间的关系,理想情况下残差应随机分布,没有明显的模式。

Training Loss Over Iterations:显示了随着模型迭代次数的增加,训练损失如何下降,表明模型的收敛情况。

最后

通过这个案例,给大家展现了这种从零实现 GBDT 的过程能帮助你更好地理解梯度提升决策树的核心原理。
最近准备了16大块的内容,124个算法问题的总结,完整的机器学习小册,免费领取~
另外,今天给大家准备了关于「深度学习」的论文合集,往期核心论文汇总,分享给大家。
点击名片,回复「深度学习论文」即可~
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~

机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
 最新文章