当前位置: 首页 > news >正文

Boosting家族 -- XGBoost分享

Boosting家族 – XGBoost分享

Boosting(提升方法) 是一种 集成学习(Ensemble Learning) 思想。
它的核心目标是:

把多个“弱分类器”(weak learners)叠加起来,形成一个“强分类器”(strong learner)。

Boosting 的基本思路

Boosting 的训练是逐步进行的(不同于随机森林的“并行训练”):

  1. 初始化模型
    用一个简单的模型(比如决策树)先预测。
  2. 计算误差(残差)
    看看模型预测得哪里错了。
  3. 训练下一个模型
    让新模型“专注”学习前面模型做错的样本。
  4. 加权组合多个模型
    把所有弱模型按照一定权重组合成一个最终强模型。
  5. 重复
    不断叠加,直到误差不再明显减少或达到设定次数。

一、什么是 XGBoost

XGBoost(Extreme Gradient Boosting) 是一种基于 梯度提升树(Gradient Boosting Decision Tree, GBDT) 的高效机器学习算法,
由陈天奇等人在 2016 年提出。

它的名字意思是:“极端梯度提升算法”——即在传统 GBDT 的基础上,进行了极致的优化。

二、核心思想

XGBoost 的核心思想与 Boosting 一致:

通过多棵“弱分类器”(通常是浅层决策树)逐步叠加,让后面的树去纠正前面树的错误,最终形成一个强大的预测模型。

三、基本工作流程

  1. 初始化模型
    设定初始预测值 F0(x)F_0(x)F0(x)

  2. 计算梯度和二阶梯度
    对每个样本计算当前模型预测误差的导数和二阶导(即残差信息)。

  3. 构建新的树(弱分类器)
    拟合这些梯度残差,构建一棵新的 CART 决策树。

  4. 计算叶子节点的权重

    wj=−∑gi∑hi+λw_j = -\frac{\sum g_i}{\sum h_i + \lambda}wj=hi+λgi

    其中:

    • gig_igi 是样本 iii 的一阶梯度
    • hih_ihi 是样本 iii 的二阶梯度
    • λ\lambdaλ 是 L2 正则化系数

    这个公式确保了在考虑正则化的情况下,找到使目标函数最小化的最优权重。

  5. 更新模型

    Fm(x)=Fm−1(x)+η⋅hm(x)F _ { m } ( x ) = F _ { m - 1 } ( x ) + \eta \cdot h _ { m } ( x )Fm(x)=Fm1(x)+ηhm(x)

    其中:

    • Fm(x)F _ { m } ( x )Fm(x) 是第 mmm 轮迭代后的集成模型
    • Fm−1(x)F _ { m - 1 } ( x )Fm1(x) 是第 m−1m-1m1 轮迭代后的模型
    • η\etaη 是学习率(收缩系数)
    • hm(x)h _ { m } ( x )hm(x) 是第 mmm 轮训练的基础学习器

    这个公式体现了梯度提升的核心思想:通过逐步添加新的基础学习器来改进模型。

  6. 重复以上步骤

    直到树的数量达到设定上限或损失函数不再明显下降。

PS: 数学上更详细的推导请参考视频 XGBoost损失推导

四、XGBoost 的目标函数

XGBoost 的训练目标是最小化以下带正则化的目标函数:

Obj=∑il(yi,y^i)+∑kΩ(fk)\text{Obj} = \sum_{i} l(y_i, \hat{y}_i) + \sum_{k} \Omega(f_k)Obj=il(yi,y^i)+kΩ(fk)

其中:

  • l(yi,y^i)l(y_i, \hat{y}_i)l(yi,y^i):样本的损失函数(如平方误差、逻辑损失等);
  • Ω(fk)=γT+12λ∑jwj2\Omega(f_k) = \gamma T + \frac{1}{2} \lambda \sum_j w_j^2Ω(fk)=γT+21λjwj2:模型复杂度惩罚项。
    • TTT:树的叶子数;
    • λ\lambdaλ:L2 正则化参数;
    • γ\gammaγ:每次分裂的惩罚项。

🧠 五、XGBoost 的主要优化点

优化方向说明
🧩 二阶梯度优化不仅使用一阶导,还使用二阶导信息,使得更新方向更精确
🎯 正则化项控制模型复杂度,防止过拟合
并行分裂搜索特征级并行计算,提高训练速度
🧮 稀疏感知算法自动处理缺失值和稀疏特征
💾 缓存优化使用分块结构优化内存访问
🧠 交叉验证内置支持自动调参与早停策略(early stopping)

📊 六、XGBoost 常用参数

参数名含义
n_estimators树的数量
max_depth树的最大深度
learning_rate学习率(控制每次提升幅度)
subsample训练样本的采样比例
colsample_bytree每棵树使用的特征比例
reg_lambdaL2 正则化参数
reg_alphaL1 正则化参数
gamma最小分裂损失的惩罚项

💡 七、XGBoost 的优点总结

优点说明
训练速度快支持多线程并行、缓存优化
🧠 泛化能力强正则化项防止过拟合
🎯 预测精度高使用二阶梯度信息
💾 内存利用高效支持稀疏特征与缺失值
🔍 特征重要性分析可解释性强
🧩 兼容多任务分类、回归、排序都支持

🧪 八、简单 Python 示例

from xgboost import XGBClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score# 1. 加载数据
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)# 2. 创建模型
model = XGBClassifier(n_estimators=100, learning_rate=0.1, max_depth=3)# 3. 训练
model.fit(X_train, y_train)# 4. 预测与评估
y_pred = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))

问题:

  1. 损失越来越小的原因取决于你选的新模型,对吧?你怎么知道应该选择哪个模型去让这个差值越来越收敛?

    损失越来越小,是因为每一轮我们都在选择一个新的弱模型(比如一棵树),去最有效地拟合当前的残差(也就是上一次模型没学好的部分)。

  2. 为什么叶子节点值越大 树复杂度越高?

    简单直接的回答是:叶子节点值越大,意味着模型需要做出的预测偏差(残差)越大,为了拟合这些大的偏差,树就需要生长得更复杂(更深、有更多分支)。

直观理解:一个比喻:

想象一下你要教一个孩子识别动物。

  • 情况一(叶子节点值小):你给他看一张猫的图片,说:“这是猫。” 孩子可能只需要记住“有尖耳朵、胡须、喵喵叫”这几个简单特征就能认出来。这就像一棵简单的树,一两步就能做出正确判断。
  • 情况二(叶子节点值大):你给他看一张鸭嘴兽的图片,说:“这是鸭嘴兽。” 孩子会非常困惑,因为它像鸭子又像海狸还会下蛋!为了让他理解,你必须解释一大堆复杂的、例外的规则:“它是一只哺乳动物,但是会下蛋,嘴巴像鸭子,尾巴像海狸,生活在水边…”。这就像一棵复杂的树,需要很多层的if-else判断(规则)才能把这个“特殊案例”区分出来。

在模型中,一个“难以拟合”的样本(比如鸭嘴兽)对应的残差(真实值减去当前模型的预测值)就会很大。树模型通过创建新的分支(增加规则)来专门处理这些特殊样本,从而导致树的复杂度升高。这个新分支的叶子节点值,就是为了纠正这个大偏差而设置的,所以这个值本身也会比较大。

[OTTO分类问题](Otto Group Product Classification Challenge | Kaggle)

XGboost

import xgboost as xgb
import pandas as pd
import numpy as nptrain_pth = './dataset/otto-group/train.csv'
test_pth = './dataset/otto-group/test.csv'train_data = pd.read_csv(train_pth)
test_data = pd.read_csv(test_pth)print("训练数据形状:", train_data.shape)
print("测试数据形状:", test_data.shape)
print("训练数据列名:", train_data.columns.tolist())# 初始化训练数据集
X_train = train_data.iloc[:, 1:-1].values  # 特征列
y_train_original = train_data.iloc[:, -1].values  # 目标列print("目标变量示例:", y_train_original[:10])
print("目标变量唯一值:", np.unique(y_train_original))# 将类别标签转换为数字
unique_labels = sorted(list(set(y_train_original)))
label_to_idx = {label: idx for idx, label in enumerate(unique_labels)}
y_train = np.array([label_to_idx[label] for label in y_train_original])print("转换后的目标变量:", y_train[:10])
print("类别数量:", len(unique_labels))# 初始化测试数据集
X_test = test_data.iloc[:, 1:].values  # 跳过第一列(ID)print("训练特征形状:", X_train.shape)
print("测试特征形状:", X_test.shape)# 转换为 DMatrix 格式
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test)# 定义模型参数 - 改为输出概率
params = {'booster': 'gbtree',          # 使用基于树的模型'objective': 'multi:softprob', # 改为 softprob 输出概率'num_class': len(unique_labels),  # 类别数量'eta': 0.1,                   # 学习率'max_depth': 6,               # 树的最大深度'subsample': 0.8,             # 样本采样比例'colsample_bytree': 0.8,      # 特征采样比例'gamma': 0.1,                 # 节点分裂的最小损失'lambda': 1.0,                # L2正则化系数'seed': 42                    # 随机种子
}# 模型训练
epoch_num = 1300
print("开始训练 XGBoost 模型...")
model = xgb.train(params, dtrain, epoch_num)
print("训练完成!")# 模型预测 - 返回概率
y_pred_proba = model.predict(dtest)print("预测概率矩阵形状:", y_pred_proba.shape)
print("预测概率示例(前5个样本):")
print(y_pred_proba[:5])# 生成类别名称(Class_1 到 Class_9)
class_columns = [f'Class_{i+1}' for i in range(len(unique_labels))]# 创建提交文件
if 'id' in test_data.columns:ids = test_data['id']
else:# 如果测试数据没有id列,使用行号(从1开始)ids = range(1, len(y_pred_proba) + 1)# 创建包含概率的DataFrame
submission_proba = pd.DataFrame(y_pred_proba, columns=class_columns)
submission_proba.insert(0, 'id', ids)  # 在第一列插入id# 保存预测结果
submission_proba.to_csv('./dataset/otto-group/otto_xgboost_predictions_proba.csv', index=False)
print("概率预测结果已保存到 ./dataset/otto-group/otto_xgboost_predictions_proba.csv")

epoch = 100

在这里插入图片描述

epoch = 1000

在这里插入图片描述

epoch = 2000

在这里插入图片描述

epoch = 5000

在这里插入图片描述

epoch = 10000

在这里插入图片描述

最佳:

epoch = 1000

在这里插入图片描述

Linear neural network

import torch
import pandas as pd
import numpy as np
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optimbatch_size = 64
class OttoDataset(Dataset):def __init__(self, filepath, train=True):self.df = pd.read_csv(filepath)self.train = trainif self.train:self.features = self.df.iloc[:, 1:-1].valuesself.labels = self.df.iloc[:, -1].values#   标签编码(后面待学习)self.unique_labels = sorted(list(set(self.labels)))self.label_to_idx = {label: idx for idx, label in enumerate(self.unique_labels)}self.labels = torch.tensor([self.label_to_idx[label] for label in self.labels], dtype=torch.long)else:self.features=self.df.iloc[:, 1:].valuesself.labels = None# print(self.labels)self.features = torch.tensor(self.features, dtype=torch.float32)def __getitem__(self, idx):if self.train:return self.features[idx], self.labels[idx]else:return self.features[idx]def __len__(self):return len(self.features)class Model(torch.nn.Module):def __init__(self):super(Model, self).__init__()self.linear1 = torch.nn.Linear(93, 128)self.linear2 = torch.nn.Linear(128, 64)self.linear3 = torch.nn.Linear(64, 32)self.linear4 = torch.nn.Linear(32, 16)self.linear5 = torch.nn.Linear(16, 9)self.dropout = torch.nn.Dropout(0.2)def forward(self, x):x = F.relu(self.linear1(x))x = F.relu(self.linear2(x))x = F.relu(self.linear3(x))x = F.relu(self.linear4(x))return self.linear5(x)train_dataset = OttoDataset('./dataset/otto-group/train.csv', train=True)
train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True,num_workers=2)
test_dataset = OttoDataset('./dataset/otto-group/test.csv', train=False)
test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle=False,num_workers=2)model = Model()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.5)def train(epoch):model.train()running_loss = 0.0for batch_idx, data in enumerate(train_loader, 0):inputs, target = dataoptimizer.zero_grad()output = model(inputs)loss = criterion(output, target)loss.backward()optimizer.step()running_loss += loss.item()if batch_idx % 300 == 299:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))running_loss = 0.0
def test():model.eval()all_preds = []test_ids= []with torch.no_grad():for data in test_loader:outputs = model(data)# 转换为概率分布probs = F.softmax(outputs, dim=1).cpu().numpy()all_preds.append(probs)all_preds = np.vstack(all_preds)test_df = pd.read_csv('./dataset/otto-group/test.csv')test_ids = test_df['id'].valuessubmission = pd.DataFrame(all_preds, columns=['Class_1', 'Class_2', 'Class_3', 'Class_4','Class_5', 'Class_6', 'Class_7', 'Class_8', 'Class_9'])submission.insert(0, 'id', test_ids)submission.to_csv('submission.csv', index = False)print("预测结果已保存到 submission.csv")if __name__ == '__main__':for epoch in range(100):train(epoch)test()

在这里插入图片描述

可见排行榜分数

在这里插入图片描述

http://www.dtcms.com/a/537585.html

相关文章:

  • win服务器做网站做外贸的国际网站有哪些
  • 重庆市建设工程信息网站诚信分wordpress计费搜索
  • “心灵灯塔”AI辅助心理自我干预全流程指南
  • 学会网站 建设广州网站设计公司哪里济南兴田德润怎么联系
  • 网站结构优化包括什么查找企业资料的网站
  • 高并发购物商城系统搭建实战
  • [人工智能-大模型-95]:大模型应用层 - RAG, 大模型,应用之间的关系
  • CrossFormer 论文详解教程
  • 【Java】@Autowired警告问题,使用@RequiredArgsConstructor
  • 免费推广网站2023网页设计实训心得500字
  • wordpress快站怎么样哪一个做h5的网站好
  • 大模型入门学习路径(个人学习路径的分享)
  • 医药平台网站建设国外h5制作网站模板
  • wordpress博客收录查询西安网站优化公司
  • Docker基础教程 - 容器化部署入门指南
  • 谷歌网站开发用什么框架软件技术专升本需要考什么
  • 企业百度网站建设做模具行业的网站
  • 030-Spring AI Alibaba OpenAI Chat 功能完整案例
  • Java全栈学习笔记43
  • 现在网站做多宽的杭州网络推广运营公司
  • 电子商务网站技术广告公司业务员小刘与客户马经理
  • 绑定网站山西网架公司
  • 《蒙台梭利的早教全书》笔记(二)-“非干预教育法”
  • 网站制作方案介绍及要求aspaccess做网站
  • 怎么建立图片文件深圳网站优化咨询
  • 三合一网站方案昆明网站建设制作
  • 云南网站建百度搜索关键词热度
  • 【STM32项目开源】STM32单片机多功能饮水机系统
  • redis-哨兵模式配置整理
  • Cookie 快速导入浏览器