所有文章 > AI驱动 > 突破最强算法模型,GBDT !!

突破最强算法模型,GBDT !!

今儿给大家分享另外一个非常重要的算法:GBDT !~

首先说,GBDT (Gradient Boosting Decision Tree) 是一种集成学习算法,它通过组合多个决策树模型来提升预测效果。这个名字有点复杂,但其实它背后的思想并不难理解。

我们从头讲起,分几个步骤来说明 GBDT 的工作原理,并结合一个简单的例子来帮助大家理解。

简介GBDT

什么是决策树?

决策树是一个常见的机器学习模型,它的结构就像一棵树,通过逐步问一些问题,来将数据分类或做出预测。举个例子,如果你要预测今天要不要带伞,决策树可能问:

  • 今天会下雨吗?(是 / 否)
  • 天气预报说下雨的概率高吗?(高 / 低)

这些问题的答案会引导你做出最终的决定(带伞或不带伞)。决策树很直观,但它的表现可能不够完美,有时候一棵树会有偏差,不能准确预测。

什么是集成学习?

集成学习的想法是,把多个模型的预测结果结合起来,往往能比单个模型表现得更好。你可以把它想象成:一群人一起做决定,可能比一个人单独做决定更靠谱。GBDT 就是使用多棵决策树来改进模型效果。

GBDT 的核心思想

GBDT 全称为梯度提升决策树。它是这样工作的:

1. 训练第一棵树:一开始,GBDT 训练一棵简单的决策树,尽量去拟合数据。比如我们预测房价,第一棵树的预测结果可能不是很准确,但它会尽力给出一个初步的房价预测。

2. 计算误差:接着,GBDT 会计算这棵树的预测和真实结果的差距(误差)。这个误差告诉我们模型哪里做得不好。

3. 训练第二棵树:第二棵树的任务是专门去修正第一棵树的错误。换句话说,第二棵树学习的是第一棵树的残差,即它未能正确预测的部分。这样,第二棵树就能帮助第一棵树做出更好的预测。

4. 重复过程:这个过程会重复很多次,每次新加入的树都会去修正前一棵树的错误。最终,所有树的预测结果会被加起来,组合成一个更准确的预测。

简单案例

假设你想预测某个同学期末考试的成绩,模型会通过一些因素,比如平时的作业成绩、出勤率和模拟考试的分数,来预测最终成绩。

  • 第一棵树:一开始,决策树会根据作业成绩、出勤率、模拟考试等信息,给出一个预测值,假设预测这个同学会考 70 分,但实际这个同学考了 80 分。这时,模型就产生了 10 分的误差。
  • 第二棵树:第二棵树会尝试去拟合这 10 分的误差,比如发现「出勤率高的学生通常会考得更好」,于是第二棵树可能给出一个 5 分的修正,新的预测就是 70 + 5 = 75 分。
  • 第三棵树:再继续,第三棵树继续去拟合剩下的 5 分误差,可能根据其他因素(比如平时作业成绩)给出一个 3 分的调整。于是最后的预测值就是 75 + 3 = 78 分。

通过这样的迭代过程,每棵树都在修正前面的误差,最终模型的预测会越来越接近真实值。

GBDT 就像是多个决策树的团队协作,每棵树专注于改正前面树犯的错误,逐步逼近正确的预测结果。通过这个「修正误差」的过程,GBDT 的预测效果通常非常好,尤其在处理回归问题和分类问题时。

有了这个浅显易懂的解释后,咱们下面详细聊聊其原理性的内容~

GBDT原理及案例

要详细推导 GBDT 的公式,并实现一个从零开始的 Python 案例,首先我们需要一步步从 GBDT 的核心思想出发,包括梯度的概念、损失函数的优化过程,最后手动实现算法。然后通过一个 Kaggle 数据集进行实践,分析数据并绘制可视化图形。这里我们分成几个步骤:

1. GBDT 原理

GBDT 是基于梯度提升算法决策树回归。它的核心思想是通过构建多个弱学习器(通常是决策树),并且每次都去拟合当前模型的残差,从而逐步逼近真实值。

梯度提升的基本步骤

1. 初始化模型

首先,我们可以用一个常数来初始化模型:

2. 迭代训练

3. 更新模型

4. 最终模型

经过 次迭代后,最终的模型是所有树的线性组合:

2. GBDT 案例

导入并预处理数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split

# 读取数据
df = pd.read_csv('house-prices-advanced-regression-techniques.csv')

# 查看数据概况
print(df.head())

数据预处理

  • 选择几个有代表性的特征用于训练。
  • 处理缺失值。
  • 对数据进行归一化或标准化。
# 简单选择特征和目标值
features = ['OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
X = df[features].fillna(0)
y = df['SalePrice']

# 数据标准化
X = (X - X.mean()) / X.std()

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

GBDT 基本实现

我们手动实现一个 GBDT 模型,从零开始训练决策树,计算残差,并逐步更新模型。

# 自定义一个简单的决策树桩
class DecisionTreeStump:
def __init__(self):
self.feature_index = None
self.threshold = None
self.left_value = None
self.right_value = None

def fit(self, X, y):
# 找到最佳的分裂点
best_loss = float('inf')
for feature_index in range(X.shape[1]):
thresholds = np.unique(X[:, feature_index])
for threshold in thresholds:
left_mask = X[:, feature_index] <= threshold
right_mask = X[:, feature_index] > threshold
left_value = np.mean(y[left_mask])
right_value = np.mean(y[right_mask])
loss = np.sum((y[left_mask] - left_value) ** 2) + np.sum((y[right_mask] - right_value) ** 2)
if loss < best_loss:
best_loss = loss
self.feature_index = feature_index
self.threshold = threshold
self.left_value = left_value
self.right_value = right_value

def predict(self, X):
predictions = np.zeros(X.shape[0])
left_mask = X[:, self.feature_index] <= self.threshold
right_mask = X[:, self.feature_index] > self.threshold
predictions[left_mask] = self.left_value
predictions[right_mask] = self.right_value
return predictions

# 梯度提升算法
class GradientBoostingRegressor:
def __init__(self, n_estimators=100, learning_rate=0.1):
self.n_estimators = n_estimators
self.learning_rate = learning_rate
self.trees = []

def fit(self, X, y):
# 初始化模型为样本均值
F_m = np.mean(y)
self.F_0 = F_m
residuals = y - F_m
for _ in range(self.n_estimators):
tree = DecisionTreeStump()
tree.fit(X, residuals)
predictions = tree.predict(X)
residuals = residuals - self.learning_rate * predictions
self.trees.append(tree)

def predict(self, X):
# 开始预测
F_m = np.ones(X.shape[0]) * self.F_0
for tree in self.trees:
F_m += self.learning_rate * tree.predict(X)
return F_m

模型训练与评估

我们可以训练模型并进行预测:

# 训练模型
model = GradientBoostingRegressor(n_estimators=50, learning_rate=0.1)
model.fit(X_train.values, y_train.values)

# 预测
y_pred = model.predict(X_test.values)

# 评估结果
from sklearn.metrics import mean_squared_error
mse = mean_squared_error(y_test, y_pred)
print(f'MSE: {mse}')

可视化分析

将结果与实际值进行可视化对比,并展示残差的变化趋势。

# 绘制预测值与实际值的对比图
plt.figure(figsize=(10,6))
plt.scatter(y_test, y_pred, color='red')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2, color='blue')
plt.xlabel('Actual Prices')
plt.ylabel('Predicted Prices')
plt.title('Actual vs Predicted House Prices')
plt.show()
# 绘制残差分布
residuals = y_test - y_pred
plt.figure(figsize=(10,6))
sns.histplot(residuals, kde=True, color="green")
plt.title('Residuals Distribution')
plt.xlabel('Residuals')
plt.ylabel('Frequency')
plt.show()

完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# 读取数据
df = pd.read_csv('house-prices-advanced-regression-techniques.csv')

# 简单选择特征和目标值
features = ['OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
X = df[features].fillna(0)
y = df['SalePrice']

# 数据标准化
X = (X - X.mean()) / X.std()

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=

42)

# 自定义一个简单的决策树桩
class DecisionTreeStump:
def __init__(self):
self.feature_index = None
self.threshold = None
self.left_value = None
self.right_value = None

def fit(self, X, y):
# 找到最佳的分裂点
best_loss = float('inf')
for feature_index in range(X.shape[1]):
thresholds = np.unique(X[:, feature_index])
for threshold in thresholds:
left_mask = X[:, feature_index] <= threshold
right_mask = X[:, feature_index] > threshold
left_value = np.mean(y[left_mask])
right_value = np.mean(y[right_mask])
loss = np.sum((y[left_mask] - left_value) ** 2) + np.sum((y[right_mask] - right_value) ** 2)
if loss < best_loss:
best_loss = loss
self.feature_index = feature_index
self.threshold = threshold
self.left_value = left_value
self.right_value = right_value

def predict(self, X):
predictions = np.zeros(X.shape[0])
left_mask = X[:, self.feature_index] <= self.threshold
right_mask = X[:, self.feature_index] > self.threshold
predictions[left_mask] = self.left_value
predictions[right_mask] = self.right_value
return predictions

# 梯度提升算法
class GradientBoostingRegressor:
def __init__(self, n_estimators=100, learning_rate=0.1):
self.n_estimators = n_estimators
self.learning_rate = learning_rate
self.trees = []

def fit(self, X, y):
# 初始化模型为样本均值
F_m = np.mean(y)
self.F_0 = F_m
residuals = y - F_m
for _ in range(self.n_estimators):
tree = DecisionTreeStump()
tree.fit(X, residuals)
predictions = tree.predict(X)
residuals = residuals - self.learning_rate * predictions
self.trees.append(tree)

def predict(self, X):
# 开始预测
F_m = np.ones(X.shape[0]) * self.F_0
for tree in self.trees:
F_m += self.learning_rate * tree.predict(X)
return F_m

# 训练模型
model = GradientBoostingRegressor(n_estimators=50, learning_rate=0.1)
model.fit(X_train.values, y_train.values)

# 预测
y_pred = model.predict(X_test.values)

# 评估结果
mse = mean_squared_error(y_test, y_pred)
print(f'MSE: {mse}')

# 绘制预测值与实际值的对比图
plt.figure(figsize=(10,6))
plt.scatter(y_test, y_pred, color='red')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2, color='blue')
plt.xlabel('Actual Prices')
plt.ylabel('Predicted Prices')
plt.title('Actual vs Predicted House Prices')
plt.show()

# 绘制残差分布
residuals = y_test - y_pred
plt.figure(figsize=(10,6))
sns.histplot(residuals, kde=True, color="green")
plt.title('Residuals Distribution')
plt.xlabel('Residuals')
plt.ylabel('Frequency')
plt.show()

通过手动实现完整的 GBDT 算法,展示了从零开始如何构建一个简单的 GBDT 回归模型,同时通过可视化展示了预测效果和残差的分布。

文章转自微信公众号@深夜努力写Python