机器学习——集成学习详解
本文系统介绍了集成学习的两种核心思想:Bagging和Boosting。Bagging通过有放回抽样并行训练多个弱学习器,采用平权投票决策,代表算法是随机森林;Boosting则串行训练,关注前序模型错误样本,通过加权投票集成,代表算法是Adaboost。文章详细讲解了随机森林的构建过程及Python实现,并以泰坦尼克号数据为例进行演示。对于Adaboost,重点阐述了其自适应提升机制、权值调整策
一、集成学习思想
- 什么是集成学习?
集成学习是机器学习中的一种思想,它通过多个模型的组合形成一个精度更高的模型,参与组合的模型成为弱学习器(基学习器)。训练时,使用训练集依次训练出这些弱学习器,对未知的样本进行预测时,使用这些弱学习器联合进行预测,因此,集成学习不是一种新的算法,而是将机器学习的算法集成
- Bagging思想:
- 有放回的抽样(booststrap抽样)产生不同的训练集,从而训练不同的学习器
- 通过平权投票、多数表决的方式决定预测结果
- 弱学习器可以并行训练

目标:把图中的圈和方块进行分类
- Boosting思想:
- 每一个训练器重点关注前一个训练器不足的地方进行训练
- 通过加权投票的方式,得出预测结果
- 串行的训练方式

- 对比:
| bagging | boosting | |
|---|---|---|
| 数据采样 | 对数据进行有放回的采样训练 | 全部样本,根据前一轮学习结果调整数据的重要性 |
| 投票方式 | 所有学习器平权投票 | 对学习器进行加权投票 |
| 学习顺序 | 并行,每个学习器没有依赖关系 | 串行,学习有先后顺序 |
二、Bagging思想——随机森林算法
- 构建过程:
- 随机选取数据有放回抽样
- 随机选取特征
- 训练弱学习器
- 重复1-3训练n个
- 平权投票

- API:

- 案例:使用泰坦尼克号数据预测存活概率
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
data = pd.read_csv("train.csv")
x = data[["Pclass" , "Age" , "Sex"]]
y = data["Survived"]
x["Age"].fillna(x["Age"].mean(), inplace=True)
x = pd.get_dummies(x)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=22)
# CART树
dtc = DecisionTreeClassifier(max_depth=10 , random_state=22)
dtc.fit(x_train , y_train)
y_pre1 = dtc.predict(x_test)
accuracy_score(y_test, y_pre1)
# 随机森林
rfc = RandomForestClassifier(n_estimators=10 , max_depth=10 , random_state=22)
rfc.fit(x_train , y_train)
y_pre2 = rfc.predict(x_test)
accuracy_score(y_test, y_pre2)
# 网格搜索寻找超参数
param_grid = {"n_estimators": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] , "max_depth": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] , "min_samples_split": [2, 4, 6, 8] , "random_state": [22]}
estimator = RandomForestClassifier()
grid_search = GridSearchCV(estimator, param_grid)
grid_search.fit(x_train , y_train)
print(grid_search.best_params_)
print(grid_search.best_estimator_)
y_pre3 = grid_search.predict(x_test)
print(accuracy_score(y_test, y_pre3))
三、Boosting思想——Adaboost算法
- Adaptive Boosting(自适应提升)基于 Boosting思想实现的一种集成学习算法核心思想是通过逐步提高那些被前一步分类错误的样本的权重来训练一个强分类器
- 特点:训练时,样本具有权重,并且在训练过程中动态调整。被分错的样本的样本会加大权重,算法更加关注难分的样本
- 核心步骤:
- 权值调整:AdaBoost算法提高那些被前一轮基分类器错误分类样本的权值,而降低那些被正确分类样本的权值。从而使得那些没有得到正确分类的样本,由于权重的加大而受到后一轮基分类器的更大关注
- 基分类器组合:AdaBoost采用加权多数表决的方法
- 分类误差率较小的弱分类器的权值大,在表决中起较大作用
- 分类误差率较大的弱分类器的权值小,在表决中起较小作用
- 算法推导:
- 初始化训练数据权重相等,训练第1个学习器
- 如果有100个样本,则每个样本的初始化权重为:1/100
- 根据预测结果找一个错误率最小的分裂点,计算更新:样本权值、模型权值
- 根据新权重的样本集训练第2个学习器
- 迭代训练在前一个学习器的基础上,根据新的样本权重训练当前学习器,直到训练处m个弱学习器
- m个弱学习器集成预测公式:H(x)=sign(∑i=1maihi(x))\mathrm{H}(\mathrm{x})=\mathrm{sign}(\sum_{i=1}^ma_ih_i(x))H(x)=sign(∑i=1maihi(x))
- 模型权重计算公式:at=12ln(1−εtεt),at为模型权重,εt表示第t个弱学习器的错误率a_\mathrm{t}=\frac{1}{2}\ln(\frac{1-\varepsilon_t}{\varepsilon_t})\quad,a_\mathrm{t}为模型权重,\varepsilon_t表示第t个弱学习器的错误率at=21ln(εt1−εt),at为模型权重,εt表示第t个弱学习器的错误率
- 样本权重计算公式:
Dt+1(x)=Dt(x)Zt∗{e−at,预 测 值 = 真 实 值 eat,预 测 值 ≈真 实 值 ,{Zt为归一化值(所有样本权重的总和)Dt(x)为样本权重αt为模型权重\mathrm{D} _{\mathrm{t+ 1}}( x) = \frac {\mathrm{D} _{\mathrm{t} }( x) }{Z_{t}}* \begin{cases} e^{- a_{t}}, \text{预 测 值 }= \text{ 真 实 值 }\\ e^{a_{t}}, \text{预 测 值 }\approx \text{真 实 值 }& \end{cases},\begin{cases}Z_t为归一化值(所有样本权重的总和)\\D_t(x) 为样本权重\\α_t 为模型权重\end{cases}Dt+1(x)=ZtDt(x)∗{e−at,预 测 值 = 真 实 值 eat,预 测 值 ≈真 实 值 ,⎩ ⎨ ⎧Zt为归一化值(所有样本权重的总和)Dt(x)为样本权重αt为模型权重
对于数据集:
- 构建第一个基学习器:
- 寻找最优分裂点:
- 对特征值 x 进行排序,确定分裂点为:0.5、1.5、2.5、3.5、4.5、5.5、6.5、7.5、8.5
- 当以 0.5 为分裂点时,有 5 个样本分类错误
- 当以 1.5 为分裂点时,有 4 个样本分类错误
- 当以 2.5 为分裂点时,有 3 个样本分类错误
- 当以 3.5 为分裂点时,有 4 个样本分类错误
- 当以 4.5 为分裂点时,有 5 个样本分类错误
- 当以 5.5 为分裂点时,有 4 个样本分类错误
- 当以 6.5 为分裂点时,有 5 个样本分类错误
- 当以 7.5 为分裂点时,有 4 个样本分类错误
- 当以 8.5 为分裂点时,有 3 个样本分类错误
- 最终,选择以 2.5 作为分裂点,计算得出基学习器错误率为:3/10=0.3
- 计算模型权重: at=12ln(1−0.30.3)=0.4236a_\mathrm{t}=\frac{1}{2}\ln(\frac{1-0.3}{0.3})\quad=0.4236at=21ln(0.31−0.3)=0.4236
- 更新样本权值:
- 分类正确样本为:1、2、3、4、5、6、10 共 7 个,其计算公式为:e-αt,则正确样本权重变化系数为:e-0.4236 =
0.6547- 分类错误样本为:7、8、9 共 3 个,其计算公式为:eαt,则错误样本权重变化系数为:e0.4236 =
1.5275- 样本 1、2、3、4、5、6、10 权重值为:0.6547⋅0.1=0.065470.6547\cdot0.1 = 0.065470.6547⋅0.1=0.06547
- 样本 7、8、9 的样本权重值为:1.5275⋅0.1=0.152751.5275\cdot0.1=0.152751.5275⋅0.1=0.15275
- 归一化 Zt 值为:0.06547⋅7+0.15275⋅3=0.91650.06547\cdot 7 + 0.15275\cdot3 = 0.91650.06547⋅7+0.15275⋅3=0.9165
- 样本 1、2、3、4、5、6、10 最终权重值为: 0.065470.9165=0.07143\frac{0.06547}{0.9165}=0.071430.91650.06547=0.07143
- 样本 7、8、9 的样本权重值为:0.152750.9165=0.1667\frac{0.15275}{0.9165}=0.16670.91650.15275=0.1667
- 构建第二个基学习器:
寻找最优分裂点:
- 对特征值 x 进行排序,确定分裂点为:0.5、1.5、2.5、3.5、4.5、5.5、6.5、7.5、8.5
- 当以 0.5 为分裂点时,有 5 个样本分类错误,错误率为:0.07143 * 5 = 0.35715
- 当以 1.5 为分裂点时,有 4 个样本分类错误,错误率为:0.07143 * 1 + 0.16667 * 3 = 0.57144
- 当以 2.5 为分裂点时,有 3 个样本分类错误,错误率为:0.16667 * 3 = 0.57144
- 以此类推
- 当以 8.5 为分裂点时,有 3 个样本分类错误,错误率为:0.07143 * 3 = 0.21429
- 最终,选择以 8.5 作为分裂点,计算得出基学习器错误率为:0.21429
计算模型权重: at=12ln(1−0.214290.21429)=0.64963a_\mathrm{t}=\frac{1}{2}\ln(\frac{1-0.21429}{0.21429})\quad=0.64963at=21ln(0.214291−0.21429)=0.64963
分类正确的样本:1、2、3、7、8、9、10,其权重调整系数为:e-0.64963 = 0.5222
分类错误的样本:4、5、6,其权重调整系数为:e0.64963 =1.9148
分类正确样本权重值:
- 样本 0、1、2、9 为:0.5222⋅0.07143=0.03730.5222\cdot0.07143=0.03730.5222⋅0.07143=0.0373
- 样本 6、7、8 为:0.5222⋅0.1667=0.0870.5222\cdot0.1667=0.0870.5222⋅0.1667=0.087
分类错误样本权重值:1.9148⋅0.07143=0.13681.9148\cdot0.07143=0.13681.9148⋅0.07143=0.1368
归一化 Zt 值为:0.0373⋅4+0.087⋅3+0.1368⋅3=0.82060.0373\cdot4 + 0.087\cdot3 + 0.1368\cdot3 = 0.82060.0373⋅4+0.087⋅3+0.1368⋅3=0.8206
最终权重:
- 样本 0、1、2、9 为 :0.03730.8206=0.0455\frac{0.0373}{0.8206}=0.04550.82060.0373=0.0455
- 样本 6、7、8 为:0.0870.8206=0.1060\frac{0.087}{0.8206}=0.10600.82060.087=0.1060
- 样本 3、4、5 为:0.13680.8206=0.1667\frac{0.1368}{0.8206}=0.16670.82060.1368=0.1667
>
构建第四个基学习器:
强学习器: H(x)=sign(0.4236⋆h1(x)+0.64963⋆h2(x)+0.7515⋆h3(x))\mathrm{H}(\mathrm{x})=\mathrm{sign}(0.4236^{\star}h_{1}(x)+0.64963^{\star}h_{2}(x)+0.7515^{\star}h_{3}(x))H(x)=sign(0.4236⋆h1(x)+0.64963⋆h2(x)+0.7515⋆h3(x))
- 案例:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
# 数据预处理
data = pd.read_csv("wine0501.csv")
data = data[data["Class label"] != 1]
x = data[["Alcohol" , "Hue"]].values
y = data["Class label"]
y = LabelEncoder().fit_transform(y)
# 划分
x_train , x_test , y_train , y_test = train_test_split(x , y , test_size = 0.2, random_state = 22)
# 训练
dtc = DecisionTreeClassifier(criterion = "entropy" , max_depth=10 , random_state = 22)
estimator = AdaBoostClassifier(estimator=dtc , n_estimators=100 , learning_rate=0.1 , random_state=22)
dtc.fit(x_train , y_train )
estimator.fit(x_train , y_train)
# 预测评估
y_pre1 = dtc.predict(x_test)
y_pre2 = estimator.predict(x_test)
print("===========dtc===========")
print(dtc.score(x_test , y_test))
print(dtc.score(x_test , y_test))
print("===========estimator===========")
print(estimator.score(x_test , y_test))
print(accuracy_score(y_test, y_pre2))
四、Boosting思想——GBDT算法
- 提升树:通过拟合残差的思想来进行提升,其中残差:真实值 - 预测值
- 梯度提升树:通过梯度下降的近似方法,利用损失函数的负梯度作为提升树算法中的残差近似值
- 数学公式:
- 前一轮迭代得到的强学习器是:fi−1(x)f_{i-1}(x)fi−1(x)
- 损失函数为平方损失是:L(y,fi−1(x))L(y,f_{i-1}(x))L(y,fi−1(x))
- 本轮迭代的目标是找到一个弱学习器:ht(x)h_t(x)ht(x)
- 让本轮的损失最小化:L(y,fi(x))=L(y,fi−1(x))+ht(x)=(y−fi−1(x)−ht(x))2L(y,f_i(x))=L(y,f_{i-1}(x))+h_t(x)=(y-f_{i-1}(x)-h_t(x))^2L(y,fi(x))=L(y,fi−1(x))+ht(x)=(y−fi−1(x)−ht(x))2
- 则要拟合的负梯度为:−[∂L(y,f(xi))∂f(xi)]=yi−f(xi)-\left[\frac{\partial\mathrm{L}(\mathrm{y},\mathrm{f}(\mathrm{x}_\mathrm{i}))}{\partial\mathrm{f}(\mathrm{x}_\mathrm{i})}\right]=\mathrm{y}_\mathrm{i}-\mathrm{f}(\mathrm{x}_\mathrm{i})−[∂f(xi)∂L(y,f(xi))]=yi−f(xi)
- 已知
- 初始化弱学习器(CART树):
- 当模型预测值为何值时,会使得第一个弱学习器的平方误差最小(即损失函数对f(xi)f(x_i)f(xi)的导数,并令导数为0)
- 损失函数:L(y,f(x))=12∑i=1n(yi−f(xi))2L(y,f(x))=\frac{1}{2}\sum_{i=1}^{n}(y_{i}-f(x_{i}))^{2}L(y,f(x))=21i=1∑n(yi−f(xi))2
- 求导:∂L(y,f(x))∂f(xi)=∑i=1n(yi−f(xi))∗(yi−f(xi))′=∑i=1n(yi−f(xi))∗(−1)=∑i=1n(−yi+f(xi))=0\begin{aligned} \frac{\partial\mathrm{L}(y,\mathrm{f}(\mathrm{x}))}{\partial\mathrm{f}(x_{i})}=\sum_{i=1}^{n}(y_{i}-f(x_{i}))*(y_{i}-f(x_{i}))^{\prime} \\ =\sum_{i=1}^{n}(y_{i}-f(x_{i}))*(-1) =\sum_{i=1}^{n}(-y_{i}+f(x_{i}))=0 \end{aligned}∂f(xi)∂L(y,f(x))=i=1∑n(yi−f(xi))∗(yi−f(xi))′=i=1∑n(yi−f(xi))∗(−1)=i=1∑n(−yi+f(xi))=0
- 化简:nf(xi)=∑i=1nyi⟶f(xi)=∑i=1nyin\mathrm{nf(x_i)}=\sum_{i=1}^\mathrm{n}y_i \longrightarrow\mathrm{f(x_i)}=\frac{\sum_{i=1}^\mathrm{n}y_i}{n}nf(xi)=i=1∑nyi⟶f(xi)=n∑i=1nyi
- 因此,初始化树桩输出值为均值时,可使得第一个弱学习器的平方误差最小
- 第一轮基学习的预测值为:(5.56+5.7+5.91+6.4+6.8+7.05+8.9+8.7+9+9.05)/10=7.31
- 负梯度(残差值):目标值 - 预测值
- 构建第一个弱学习器:
上表中平方损失计算过程说明(以切分点1.5为例):
切分点1.5 将数据集分成两份 [5.56],[5.56 5.7 5.91 6.4 6.8 7.05 8.9 8.7 9. 9.05]
第一份的平均值为5.56 ;第二份数据的平均值为(5.7+5.91+6.4+6.8+7.05+8.9+8.7+9+9.05)/9 = 7.5011
由于是回归树,每份数据的平均值即为预测值,则可以计算误差,第一份数据的误差为0,第二份数据的平方误差为 : (5.70−7.5011)2+(5.91−7.5011)2+...+(9.05−7.5011)2=15.72308(5.70-7.5011)^2+(5.91-7.5011)^2+...+(9.05-7.5011)^2 = 15.72308(5.70−7.5011)2+(5.91−7.5011)2+...+(9.05−7.5011)2=15.72308
同理,依次计算2.5、3.5的平方损失
发现以6.5划分时,平方损失最小
因此左预测值:f1(x)=(−1.75−1.61−1.4−0.91−0.51−0.26)/6=−1.07f_1(x)=(-1.75-1.61-1.4-0.91-0.51-0.26)/6=-1.07f1(x)=(−1.75−1.61−1.4−0.91−0.51−0.26)/6=−1.07
因此右预测值:f1(x)=(1.59+1.39+1.69+1.74)/4=1.6f_1(x)=(1.59+1.39+1.69+1.74)/4=1.6f1(x)=(1.59+1.39+1.69+1.74)/4=1.6
以 6.5 作为切分点损失最小,构建决策树如下:
- 构建第二个弱学习器:
- 以 3.5 作为切分点损失最小,构建决策树如下:
- 构建第三个弱学习器:
- 以 6.5 作为切分点损失最小,构建决策树如下:
- 构建最终弱学习器:
- 以x=6为例,最终学习器的结果为:7.31+(−1.07)+0.22+0.15=6.617.31+(-1.07)+0.22+0.15=6.617.31+(−1.07)+0.22+0.15=6.61
- 案例:
import pandas as pd
from joblib.testing import param
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split , GridSearchCV
# 数据预处理
data = pd.read_csv("train.csv")
x = data[["Pclass" , "Age" , "Sex"]]
y = data["Survived"]
x["Age"].fillna(x["Age"].mean(), inplace=True)
x = pd.get_dummies(x)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=22)
# 网格搜索
estimator1 = GradientBoostingClassifier()
estimator1.fit(x_train, y_train)
estimator1.score(x_train, y_train)
parameters = {"n_estimators": [50, 100, 150, 200] , "max_depth": [2, 4, 6, 8 , 10] , "random_state": [22] }
estimator2 = GridSearchCV(estimator=estimator1, param_grid=parameters , cv=3)
estimator2.fit(x_train, y_train)
# 寻找超参数
print(estimator2.score(x_train, y_train))
print(estimator2.best_estimator_)
五、Boosting思想——XGBoost算法
- XGBoost(Extreme Gradient Boosting)是对GBDT的改进,在损失函数中加入了正则化项:obg(θ)=∑i=1NL(yi,f(xi))+∑k=1KΩ(fk)Ω(f)=γT+12λ∥w∥2obg(\theta)=\sum_{i=1}^NL\left(y_i,f\left(x_i\right)\right)+\sum_{k=1}^K\Omega(f_k) \\ \Omega(f)=\gamma T+\frac{1}{2}\lambda\|w\|^2obg(θ)=i=1∑NL(yi,f(xi))+k=1∑KΩ(fk)Ω(f)=γT+21λ∥w∥2
- γT\gamma TγT中 T 表示一棵树的叶子结点数量
- λ∥w∥2\lambda\|w\|^2λ∥w∥2中的 w 表示叶子节点输出值组成的项链,∥w∥\|w\|∥w∥向量的模:λ\lambdaλ对该项的调节系数
- 公式推导:
-
由于进行 t 次迭代时,t-1 次迭代的目标函数已知,因此可以写为:
obj(t)=∑i=1nL(yi,y^i(t))+∑k=1tΩ(fk)=∑i=1nL(yi,y^i(t−1)+ft(xi))+∑k=1t−1Ω(fk)+Ω(ft)\begin{aligned} obj^{(t)} & =\sum_{i=1}^nL\left(y_i,\hat{y}_i^{(t)}\right)+\sum_{k=1}^t\Omega\left(f_k\right) \\ & =\sum_{i=1}^nL\left(y_i,\hat{y}_i^{(\mathrm{t}-1)}+f_t\left(x_i\right)\right)+\sum_{k=1}^{t-1}\Omega\left(f_k\right)+\Omega\left(f_t\right) \end{aligned}obj(t)=i=1∑nL(yi,y^i(t))+k=1∑tΩ(fk)=i=1∑nL(yi,y^i(t−1)+ft(xi))+k=1∑t−1Ω(fk)+Ω(ft) -
泰勒公式:
f(x+Δx)=f(x)+f′(x)⋅Δx+12f′′(x)⋅Δx2+......+1n!f(n)(x)⋅Δxnf(x+\Delta x)=f(x)+f^{\prime}(x)\cdot\Delta x+\frac{1}{2}f^{\prime\prime}(x)\cdot\Delta x^2+......+\frac{1}{n!}f^{(n)}(x)\cdot\Delta x^nf(x+Δx)=f(x)+f′(x)⋅Δx+21f′′(x)⋅Δx2+......+n!1f(n)(x)⋅Δxn -
直接对目标函数求解比较困难,因此可以通过泰勒公式转换,将ft(xi)f_t(x_i)ft(xi)视为Δx\Delta xΔx:
obj(t)≈∑i=1m[L(yi,y^i(t−1))+gift(xi)+12hift2(xi)]+∑k=1t−1Ω(fk)+Ω(ft)其中{gi=∂y^t−1L(yi,y^(t−1))hi=∂y^(t−1)2L(yi,y^(t−1))obj^{(t)}\approx\sum_{i=1}^{m}\left[L\left(y_{i},\hat{y}_{i}^{(t-1)}\right)+g_{i}f_{t}\left(x_{i}\right)+\frac{1}{2}h_{i}f_{t}^{2}\left(x_{i}\right)\right]+\sum_{k=1}^{t-1}\Omega\left(f_{k}\right)+\Omega\left(f_{t}\right) \\ 其中\begin{cases} & g_{i}=\partial_{\hat{y}^{t-1}}L\left(y_i,\hat{y}^{(t-1)}\right) \\ & h_{i}=\partial_{\hat{y}^{(t-1)}}^2L\left(y_i,\hat{y}^{(t-1)}\right) \end{cases}obj(t)≈i=1∑m[L(yi,y^i(t−1))+gift(xi)+21hift2(xi)]+k=1∑t−1Ω(fk)+Ω(ft)其中{gi=∂y^t−1L(yi,y^(t−1))hi=∂y^(t−1)2L(yi,y^(t−1)) -
由于L(yi,y^i(t−1)){L\left(y_{i},\hat{y}_{i}^{(t-1)}\right)}L(yi,y^i(t−1))和∑k=1t−1Ω(fk)\sum_{k=1}^{t-1}\Omega(f_{k})∑k=1t−1Ω(fk)均为 t-1 次迭代的常量,在求导时为0,因此可以忽略
obj(t)≈∑i=1m[L(yi,y^i(t−1))+gift(xi)+12hift2(xi)]+∑k=1t−1Ω(fk)+Ω(ft)obj(t)≈∑i=1m[gift(xi)+12hift2(xi)]+Ω(ft),其中Ω(f)=γT+12λ∥w∥2obj(t)≈∑i=1m[gift(xi)+12hift2(xi)]+γT+12λ∥w∥2\begin{aligned} & obj^{(t)}\approx\sum_{i=1}^{m}[{L\left(y_{i},\hat{y}_{i}^{(t-1)}\right)}+g_{i}f_{t}(x_{i})+\frac{1}{2}h_{i}f_{t}^{2}(x_{i})]+\sum_{k=1}^{t-1}\Omega(f_{k})+\Omega(f_{t}) \\ & obj^{(t)}\approx\sum_{i=1}^{m}\left[g_{i}f_{t}\left(x_{i}\right)+\frac{1}{2}h_{i}f_{t}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{t}\right),其中\Omega(f)=\gamma T+\frac{1}{2}\lambda\|w\|^2 \\ & obj^{(t)}\approx\sum_{i=1}^m\left[g_if_t\left(x_i\right)+\frac{1}{2}h_if_t^2\left(x_i\right)\right]+\gamma T+\frac{1}{2}\lambda\|w\|^2 \end{aligned}obj(t)≈i=1∑m[L(yi,y^i(t−1))+gift(xi)+21hift2(xi)]+k=1∑t−1Ω(fk)+Ω(ft)obj(t)≈i=1∑m[gift(xi)+21hift2(xi)]+Ω(ft),其中Ω(f)=γT+21λ∥w∥2obj(t)≈i=1∑m[gift(xi)+21hift2(xi)]+γT+21λ∥w∥2 -
因此我们就从样本角度转为按照叶子结点输出角度,在上试中
- gig_igi表示每个样本的一阶导,hih_ihi表示每个样本的二阶导
- fi(xi)f_i(x_i)fi(xi)表示样本的预测值
- T 表示叶子节点的数目
- ∥w∣ 2\|w|\ ^2∥w∣ 2由叶子结点值组成向量的模
例如:10 个样本,落在 D 结点 3 个样本,落在 E 结点 2 个样本,落在 F 结点 2 个样本,落在 G 结点 3 个样本
D 结点计算: w1 * gi1 + w1 * gi2 + w1 * gi3 = (gi1 + gi2 + gi3) * w1
E 结点计算: w2 * gi4 + w2 * gi5 = (gi4 + gi5) * w2
F 结点计算: w3 * gi6 + w3 * gi6 = (gi6 + gi7) * w3
G 节点计算:w4 * gi8 + w4 * gi9 + w4 * gi10 = (gi8 + gi9 + gi10) * w4
-
由例子,我们可以尝试简化项,其中gifi(xi)g_if_i(x_i)gifi(xi):
∑i=1mgift(xi)=∑j=1T(∑i∈Ijgi)wj\sum_{i=1}^mg_if_t\left(x_i\right)=\sum_{j=1}^T\left(\sum_{i\in I_j}g_i\right)w_ji=1∑mgift(xi)=j=1∑T i∈Ij∑gi wj -
hift2(xi)h_if_t^2(x_i)hift2(xi):
∑i=1m12hift2(xi)=12∑j=1T(∑i∈Ijhi)wj2\sum_{i=1}^m\frac{1}{2}h_if_t^2\left(x_i\right)=\frac{1}{2}\sum_{j=1}^T\left(\sum_{i\in I_j}h_i\right)w_j^2i=1∑m21hift2(xi)=21j=1∑T i∈Ij∑hi wj2 -
λ∥w∥2\lambda\|w\| ^2λ∥w∥2:
12λ∣∣w∥2=12λ∑i=1Twi2\frac{1}{2}\lambda||w\|^2=\frac{1}{2}\lambda\sum_{i=1}^T{w_i}^221λ∣∣w∥2=21λi=1∑Twi2 -
因此转化为叶子结点输出角度:
obj(t)≈∑i=1m[gift(xi)+12hift2(xi)]+γT+12λ∥w∥2=∑j=1T[(∑i∈Ijgi)wj+12(∑i∈Ijhi)wj2]+γT+12λ∑j=1Twj2=∑j=1T[(∑i∈Ijgi)wj+12(∑i∈Ijhi)wj2+12λwj2]+γT=∑j=1T[(∑i∈Ijgi)wj+12(∑i∈Ijhi+λ)wj2]+γT\begin{aligned} obj^{(t)} & \approx\sum_{i=1}^{m}\left[g_{i}f_{t}\left(x_{i}\right)+\frac{1}{2}h_{i}f_{t}^{2}\left(x_{i}\right)\right]+\gamma T+\frac{1}{2}\lambda\|w\|^{2} \\ & =\sum_{j=1}^T\left[\left(\sum_{i\in I_j}g_i\right)w_j+\frac{1}{2}\left(\sum_{i\in I_j}h_i\right)w_j^2\right]+\gamma T+\frac{1}{2}\lambda\sum_{j=1}^Tw_j^2 \\ & =\sum_{j=1}^T\left[\left(\sum_{i\in I_j}g_i\right)w_j+\frac{1}{2}\left(\sum_{i\in I_j}h_i\right)w_j^2+\frac{1}{2}\lambda w_j^2\right]+\gamma T \\ & =\sum_{j=1}^T\left[\left(\sum_{i\in I_j}g_i\right)w_j+\frac{1}{2}\left(\sum_{i\in I_j}h_i+\lambda\right)w_j^2\right]+\gamma T \end{aligned}obj(t)≈i=1∑m[gift(xi)+21hift2(xi)]+γT+21λ∥w∥2=j=1∑T i∈Ij∑gi wj+21 i∈Ij∑hi wj2 +γT+21λj=1∑Twj2=j=1∑T i∈Ij∑gi wj+21 i∈Ij∑hi wj2+21λwj2 +γT=j=1∑T i∈Ij∑gi wj+21 i∈Ij∑hi+λ wj2 +γT -
令:
Gi=∑i∈Ijgi,Gi表示所有样本的一阶导之和Hi=∑i∈Ijhi,Hi表示所有样本的二阶导之和G_{i}=\sum_{i\in I_j}g_i ,G_i表示所有样本的一阶导之和\\ H_{i}=\sum_{i\in I_j}h_i,H_i表示所有样本的二阶导之和Gi=i∈Ij∑gi,Gi表示所有样本的一阶导之和Hi=i∈Ij∑hi,Hi表示所有样本的二阶导之和 -
最终:
obj(t)=∑i=1T[Giwi+12(Hi+λ)wi2]+γTobj^{(t)}=\sum_{i=1}^T\left[G_iw_i+\frac{1}{2}(H_i+\lambda)w_i^2\right]+\gamma Tobj(t)=i=1∑T[Giwi+21(Hi+λ)wi2]+γT -
求导取 w 的最优质:
wi=−GiHi+λw_i=-\frac{G_i}{H_i+\lambda}wi=−Hi+λGi -
将 w 带入目标函数求得最小值:
obj(t)=∑i=1T[Gi(−GiHi+λ)+12(Hi+λ)(−GiHi+λ)2]+γT=∑i=1T[Gi(−GiHi+λ)+12(Hi+λ)(−GiHi+λ)2]+γT=∑i=1T[−Gi2Hi+λ+12(Gi2Hi+λ)]+γT=−12∑i=1T(Gi2Hi+λ)+γT\begin{aligned} obj^{(t)} & =\sum_{i=1}^T\left[G_i\left(-\frac{G_i}{H_i+\lambda}\right)+\frac{1}{2}(H_i+\lambda)\left(-\frac{G_i}{H_i+\lambda}\right)^2\right]+\gamma T \\ & =\sum_{i=1}^T\left[G_i\left(-\frac{G_i}{H_i+\lambda}\right)+\frac{1}{2}(H_i+\lambda)\left(-\frac{G_i}{H_i+\lambda}\right)^2\right]+\gamma T \\ & =\sum_{i=1}^T\left[-\frac{G_i^2}{H_i+\lambda}+\frac{1}{2}\left(\frac{G_i^2}{H_i+\lambda}\right)\right]+\gamma T \\ & =-\frac{1}{2}\sum_{i=1}^T\left(\frac{G_i^2}{H_i+\lambda}\right)+\gamma T \end{aligned}obj(t)=i=1∑T[Gi(−Hi+λGi)+21(Hi+λ)(−Hi+λGi)2]+γT=i=1∑T[Gi(−Hi+λGi)+21(Hi+λ)(−Hi+λGi)2]+γT=i=1∑T[−Hi+λGi2+21(Hi+λGi2)]+γT=−21i=1∑T(Hi+λGi2)+γT
- 打分函数 (scoring function),它可以从树的损失函数、树的复杂度两个角度来衡量一棵树的优劣,当我们构建树时,可以用来选择树的最佳划分点:
Gain=ObjL+R−(ObjL+ObjR)=[−12(GL+GR)2HL+HR+λ+γT]−[−12(GL2HL+λ+GR2HR+λ)+γ(T+1)]=12[GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ]−γ\begin{aligned} \mathrm{Gain} & =Obj_{L+R}-(Obj_L+Obj_R) \\ & =\left[-\frac{1}{2}\frac{\left(G_{L}+G_{R}\right)^{2}}{H_{L}+H_{R}+\lambda}+\gamma T\right]-\left[-\frac{1}{2}\left(\frac{G_{L}^{2}}{H_{L}+\lambda}+\frac{G_{R}^{2}}{H_{R}+\lambda}\right)+\gamma(T+1)\right] \\ & =\frac{1}{2}\left[\frac{G_{L}^{2}}{H_{L}+\lambda}+\frac{G_{R}^{2}}{H_{R}+\lambda}-\frac{\left(G_{L}+G_{R}\right)^{2}}{H_{L}+H_{R}+\lambda}\right]-\gamma \end{aligned}Gain=ObjL+R−(ObjL+ObjR)=[−21HL+HR+λ(GL+GR)2+γT]−[−21(HL+λGL2+HR+λGR2)+γ(T+1)]=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ
- 打分函数的过程如下:
- 对树中的每个叶子结点尝试进行分裂
- 计算分裂前 - 分裂后的分数:
- 如果gain > 0,则分裂之后树的损失更小,我们会考虑此次分裂
- 如果gain< 0,说明分裂后的分数比分裂前的分数大,此时不建议分裂
- 当触发以下条件时停止分裂:
- 达到最大深度
- 叶子结点样本数量低于某个阈值
- 所有的节点在分裂不能降低损失
- API:通过
pip3 install xgboost获得
bst = XGBClassifier(n_estimators, max_depth, learning_rate, objective)

- 案例:
import pandas as pd
import numpy as np
import xgboost as xgb
from sklearn.model_selection import train_test_split , StratifiedKFold , GridSearchCV
from sklearn.metrics import classification_report
from sklearn.utils import class_weight
# 数据预处理
data = pd.read_csv("红酒品质分类.csv")
x = data.iloc[:, :-1]
y = data.iloc[:, -1] - 3
x_train , x_test , y_train , y_test = train_test_split(x, y , stratify=y , test_size = 0.2, random_state = 22)
# 保存训练集和测试集
pd.concat([x_train, y_train] , axis = 1).to_csv("x_train.csv")
pd.concat([x_test, y_test] , axis = 1).to_csv("x_test.csv")
train_data = pd.read_csv("x_train.csv")
test_data = pd.read_csv("x_test.csv")
x_train = train_data.iloc[:, :-1]
y_train = train_data.iloc[:, -1]
x_test = test_data.iloc[:, :-1]
y_test = test_data.iloc[:, -1]
# 根据类别的分布自动计算权重,使得每个类别的权重与其样本数量成反比
class_weights = class_weight.compute_sample_weight(class_weight='balanced', y=y_train)
# 分层交叉验证
spliter = StratifiedKFold(n_splits=4, shuffle=True)
param_grid = {"max_depth" :np.arange(10,100,10) , "n_estimators" :np.arange(50,100,10) , "learning_rate" :np.arange(0.1,1,0.2) }
# 使用XGBoost训练模型,其中损失函数设置为多分类
estimator1 = xgb.XGBClassifier(n_estimators=100 ,
objective='multi:softmax' ,
eval_metric='merror' ,
eta=0.01 ,
random_state=22)
# 网格搜索
estimator2 = GridSearchCV(estimator=estimator1 , param_grid=param_grid,cv=spliter)
estimator2.fit(x_train , y_train)
# 预测
y_pre = estimator2.predict(x_test)
print(classification_report(y_test, y_pre))
print(estimator2.best_params_)
print(estimator2.best_score_)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐










>













所有评论(0)