XGBoost算法Python代码实现
### XGBoost定义
class XGBoost:
def __init__(self, n_estimators=300, learning_rate=0.001,
min_samples_split=2,
min_gini_impurity=999,
max_depth=2):
# 树的棵数
self.n_estimators = n_estimators
# 学习率
self.learning_rate = learning_rate
# 结点分裂最小样本数
self.min_samples_split = min_samples_split
# 结点最小基尼不纯度
self.min_gini_impurity = min_gini_impurity
# 树最大深度
self.max_depth = max_depth
# 用于分类的对数损失
# 回归任务可定义平方损失
# self.loss = SquaresLoss()
self.loss = LogisticLoss()
# 初始化分类树列表
self.trees = []
# 遍历构造每一棵决策树
for _ in range(n_estimators):
tree = XGBoost_Single_Tree(
min_samples_split=self.min_samples_split,
min_gini_impurity=self.min_gini_impurity,
max_depth=self.max_depth,
loss=self.loss)
self.trees.append(tree)
# xgboost拟合方法
def fit(self, X, y):
y = cat_label_convert(y)
y_pred = np.zeros(np.shape(y))
# 拟合每一棵树后进行结果累加
for i in range(self.n_estimators):
tree = self.trees[i]
y_true_pred = np.concatenate((y, y_pred), axis=1)
tree.fit(X, y_true_pred)
iter_pred = tree.predict(X)
y_pred -= np.multiply(self.learning_rate, iter_pred)
# xgboost预测方法
def predict(self, X):
y_pred = None
# 遍历预测
for tree in self.trees:
iter_pred = tree.predict(X)
if y_pred is None:
y_pred = np.zeros_like(iter_pred)
y_pred -= np.multiply(self.learning_rate, iter_pred)
y_pred = np.exp(y_pred) / np.sum(np.exp(y_pred), axis=1, keepdims=True)
# 将概率预测转换为标签
y_pred = np.argmax(y_pred, axis=1)
return y_pred
这段代码定义了一个名为 XGBoost
的类,旨在实现 XGBoost 的基础功能,包括梯度提升树的训练和预测。以下是对代码的详细解读:
代码功能和实现逻辑
1. __init__
方法:初始化模型
功能:
- 初始化 XGBoost 模型的超参数,包括树的数量、学习率、节点分裂条件、树的最大深度等。
- 定义损失函数(这里为逻辑回归损失
LogisticLoss
),并初始化分类树列表self.trees
。
核心代码:
self.n_estimators = n_estimators # 树的数量
self.learning_rate = learning_rate # 学习率,用于控制每棵树的贡献
self.min_samples_split = min_samples_split # 节点最小分裂样本数
self.min_gini_impurity = min_gini_impurity # 节点最小基尼不纯度
self.max_depth = max_depth # 树的最大深度
self.loss = LogisticLoss() # 损失函数
self.trees = [] # 初始化决策树列表
说明:
- 每棵树由
XGBoost_Single_Tree
类定义,参数与整体模型的超参数保持一致。 - 逐一初始化树对象并存储在
self.trees
列表中。
2. fit
方法:训练模型
功能:
- 拟合训练数据集 ( X , y ) (X, y) (X,y)。
- 对每棵树,基于当前的残差拟合新的决策树,逐步逼近目标函数。
实现步骤:
-
初始化预测值:
使用y_pred = np.zeros(np.shape(y))
初始化所有样本的预测值为零。 -
训练每一棵树:
- 计算当前的真实值和预测值组合 ( y , y pred ) (y, y_{\text{pred}}) (y,ypred),作为树的输入。
- 调用
tree.fit(X, y_true_pred)
训练当前树。 - 使用当前树对样本进行预测,并更新累积预测值
y_pred
。
-
更新规则:
- 累积预测值更新规则:
y pred ( i + 1 ) = y pred ( i ) − η ⋅ tree.predict ( X ) y_{\text{pred}}^{(i+1)} = y_{\text{pred}}^{(i)} - \eta \cdot \text{tree.predict}(X) ypred(i+1)=ypred(i)−η⋅tree.predict(X)
其中, η \eta η 是学习率, tree.predict ( X ) \text{tree.predict}(X) tree.predict(X) 是当前树对样本的预测。
- 累积预测值更新规则:
核心代码:
y_pred = np.zeros(np.shape(y)) # 初始化预测值
for i in range(self.n_estimators):
tree = self.trees[i]
y_true_pred = np.concatenate((y, y_pred), axis=1) # 组合真实值和预测值
tree.fit(X, y_true_pred) # 训练当前树
iter_pred = tree.predict(X) # 当前树的预测值
y_pred -= np.multiply(self.learning_rate, iter_pred) # 累加预测值
3. predict
方法:模型预测
功能:
- 使用训练好的树集对测试数据 X X X 进行预测。
- 基于累积预测值,通过 softmax 转换为概率分布,再将概率转换为分类标签。
实现步骤:
-
初始化预测值:
使用y_pred = None
初始化预测值。 -
累积预测值:
- 遍历每棵树,逐一计算预测值。
- 累积预测值更新规则与训练一致:
y pred = y pred − η ⋅ tree.predict ( X ) y_{\text{pred}} = y_{\text{pred}} - \eta \cdot \text{tree.predict}(X) ypred=ypred−η⋅tree.predict(X)
-
概率转换:
- 使用 softmax 函数将累积预测值转换为概率分布:
p ( y ) = exp ( y pred ) ∑ exp ( y pred ) p(y) = \frac{\exp(y_{\text{pred}})}{\sum \exp(y_{\text{pred}})} p(y)=∑exp(ypred)exp(ypred)
- 使用 softmax 函数将累积预测值转换为概率分布:
-
分类标签转换:
- 对 softmax 的概率结果,取最大值的索引作为最终分类结果。
核心代码:
for tree in self.trees:
iter_pred = tree.predict(X)
if y_pred is None:
y_pred = np.zeros_like(iter_pred)
y_pred -= np.multiply(self.learning_rate, iter_pred) # 累积预测值
y_pred = np.exp(y_pred) / np.sum(np.exp(y_pred), axis=1, keepdims=True) # 转换为概率
y_pred = np.argmax(y_pred, axis=1) # 转换为分类标签
return y_pred
核心公式总结
-
训练时更新规则:
y pred ( i + 1 ) = y pred ( i ) − η ⋅ tree.predict ( X ) y_{\text{pred}}^{(i+1)} = y_{\text{pred}}^{(i)} - \eta \cdot \text{tree.predict}(X) ypred(i+1)=ypred(i)−η⋅tree.predict(X) -
预测时 softmax 转换:
p ( y ) = exp ( y pred ) ∑ exp ( y pred ) p(y) = \frac{\exp(y_{\text{pred}})}{\sum \exp(y_{\text{pred}})} p(y)=∑exp(ypred)exp(ypred)
总结
这段代码实现了一个基础的 XGBoost 算法,涵盖了梯度提升的核心逻辑和分类预测流程。尽管与正式的 XGBoost 实现相比有所简化,但它提供了一个清晰的框架,适合用于理解 XGBoost 的原理和实现方式。在实际应用中,可以根据需求扩展功能,提升模型性能和效率。