集成学习(一):
https://blog.csdn.net/liuxingxing_sun/article/details/115710634
集成学习(二):https://blog.csdn.net/liuxingxing_sun/article/details/115866360
origin from: datawhale
XGBoost
简介
构造目标函数
(1) 构造目标函数:
假设有K棵树,则第i个样本的输出为
y ^ i = ϕ ( x i ) = ∑ k = 1 K f k ( x i ) , f k ∈ F \hat{y}_{i}=\phi\left(\mathrm{x}_{i}\right)=\sum_{k=1}^{K} f_{k}\left(\mathrm{x}_{i}\right), \quad f_{k} \in \mathcal{F} y^i=ϕ(xi)=∑k=1Kfk(xi),fk∈F,
其中, F = { f ( x ) = w q ( x ) } ( q : R m → T , w ∈ R T ) \mathcal{F}=\left\{f(\mathbf{x})=w_{q(\mathbf{x})}\right\}\left(q: \mathbb{R}^{m} \rightarrow T, w \in \mathbb{R}^{T}\right) F={f(x)=wq(x)}(q:Rm→T,w∈RT)
因此,目标函数的构建为:
L
(
ϕ
)
=
∑
i
l
(
y
^
i
,
y
i
)
+
∑
k
Ω
(
f
k
)
\mathcal{L}(\phi)=\sum_{i} l\left(\hat{y}_{i}, y_{i}\right)+\sum_{k} \Omega\left(f_{k}\right)
L(ϕ)=i∑l(y^i,yi)+k∑Ω(fk)
其中,
∑
i
l
(
y
^
i
,
y
i
)
\sum_{i} l\left(\hat{y}_{i}, y_{i}\right)
∑il(y^i,yi)为loss function,
∑
k
Ω
(
f
k
)
\sum_{k} \Omega\left(f_{k}\right)
∑kΩ(fk)为正则化项。
(q: the structure of each tree that maps an example to the corresponding leaf index
T: number of leaves in the tree
Each 𝑓𝑘: corresponds to an independent tree structure q and leaf weights w.
Wi : score on i-th leaf)
叠加式训练
(2) 叠加式的训练(Additive Training):
给定样本 x i x_i xi, y ^ i ( 0 ) = 0 \hat{y}_i^{(0)} = 0 y^i(0)=0(初始预测),
y ^ i ( 1 ) = y ^ i ( 0 ) + f 1 ( x i ) \hat{y}_i^{(1)} = \hat{y}_i^{(0)} + f_1(x_i) y^i(1)=y^i(0)+f1(xi),
y ^ i ( 2 ) = y ^ i ( 0 ) + f 1 ( x i ) + f 2 ( x i ) = y ^ i ( 1 ) + f 2 ( x i ) \hat{y}_i^{(2)} = \hat{y}_i^{(0)} + f_1(x_i) + f_2(x_i) = \hat{y}_i^{(1)} + f_2(x_i) y^i(2)=y^i(0)+f1(xi)+f2(xi)=y^i(1)+f2(xi)…
以此类推,可以得到: y ^ i ( K ) = y ^ i ( K − 1 ) + f K ( x i ) \hat{y}_i^{(K)} = \hat{y}_i^{(K-1)} + f_K(x_i) y^i(K)=y^i(K−1)+fK(xi) ,
其中, y ^ i ( K − 1 ) \hat{y}_i^{(K-1)} y^i(K−1) 为前K-1棵树的预测结果, f K ( x i ) f_K(x_i) fK(xi) 为第K棵树的预测结果。
因此,目标函数可以分解为:
L
(
K
)
=
∑
i
=
1
n
l
(
y
i
,
y
^
i
(
K
−
1
)
+
f
K
(
x
i
)
)
+
∑
k
Ω
(
f
k
)
\mathcal{L}^{(K)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{(K-1)}+f_{K}\left(\mathrm{x}_{i}\right)\right)+\sum_{k} \Omega\left(f_{k}\right)
L(K)=i=1∑nl(yi,y^i(K−1)+fK(xi))+k∑Ω(fk)
由于正则化项也可以分解为前K-1棵树的复杂度加第K棵树的复杂度,因此:
L ( K ) = ∑ i = 1 n l ( y i , y ^ i ( K − 1 ) + f K ( x i ) ) + ∑ k = 1 K − 1 Ω ( f k ) + Ω ( f K ) \mathcal{L}^{(K)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{(K-1)}+f_{K}\left(\mathrm{x}_{i}\right)\right)+\sum_{k=1} ^{K-1}\Omega\left(f_{k}\right)+\Omega\left(f_{K}\right) L(K)=∑i=1nl(yi,y^i(K−1)+fK(xi))+∑k=1K−1Ω(fk)+Ω(fK),
由于
∑
k
=
1
K
−
1
Ω
(
f
k
)
\sum_{k=1} ^{K-1}\Omega\left(f_{k}\right)
∑k=1K−1Ω(fk)在模型构建到第K棵树的时候已经固定,无法改变,因此是一个已知的常数,可以在最优化的时候省去,故:
L
(
K
)
=
∑
i
=
1
n
l
(
y
i
,
y
^
i
(
K
−
1
)
+
f
K
(
x
i
)
)
+
Ω
(
f
K
)
\mathcal{L}^{(K)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{(K-1)}+f_{K}\left(\mathrm{x}_{i}\right)\right)+\Omega\left(f_{K}\right)
L(K)=i=1∑nl(yi,y^i(K−1)+fK(xi))+Ω(fK)
即第K轮的模型预测等于前K-1轮的模型预测y(K-1)加上ft,因此误差函数项记为l(yi,y(K-1)+ft),后面一项为正则化项。在当前步,yi以及y(K-1)都是已知值,模型学习的是ft。
泰勒级数近似
- 使用泰勒级数近似目标函数:
L ( K ) ≃ ∑ i = 1 n [ l ( y i , y ^ ( K − 1 ) ) + g i f K ( x i ) + 1 2 h i f K 2 ( x i ) ] + Ω ( f K ) \mathcal{L}^{(K)} \simeq \sum_{i=1}^{n}\left[l\left(y_{i}, \hat{y}^{(K-1)}\right)+g_{i} f_{K}\left(\mathrm{x}_{i}\right)+\frac{1}{2} h_{i} f_{K}^{2}\left(\mathrm{x}_{i}\right)\right]+\Omega\left(f_{K}\right) L(K)≃i=1∑n[l(yi,y^(K−1))+gifK(xi)+21hifK2(xi)]+Ω(fK)
其中, g i = ∂ y ^ ( t − 1 ) l ( y i , y ^ ( t − 1 ) ) g_{i}=\partial_{\hat{y}(t-1)} l\left(y_{i}, \hat{y}^{(t-1)}\right) gi=∂y^(t−1)l(yi,y^(t−1))和 h i = ∂ y ^ ( t − 1 ) 2 l ( y i , y ^ ( t − 1 ) ) h_{i}=\partial_{\hat{y}^{(t-1)}}^{2} l\left(y_{i}, \hat{y}^{(t-1)}\right) hi=∂y^(t−1)2l(yi,y^(t−1))
由于
∑
i
=
1
n
l
(
y
i
,
y
^
(
K
−
1
)
)
\sum_{i=1}^{n}l\left(y_{i}, \hat{y}^{(K-1)}\right)
∑i=1nl(yi,y^(K−1))在模型构建到第K棵树的时候已经固定,无法改变,因此是一个已知的常数,可以在最优化的时候省去,故:
L
~
(
K
)
=
∑
i
=
1
n
[
g
i
f
K
(
x
i
)
+
1
2
h
i
f
K
2
(
x
i
)
]
+
Ω
(
f
K
)
\tilde{\mathcal{L}}^{(K)}=\sum_{i=1}^{n}\left[g_{i} f_{K}\left(\mathbf{x}_{i}\right)+\frac{1}{2} h_{i} f_{K}^{2}\left(\mathbf{x}_{i}\right)\right]+\Omega\left(f_{K}\right)
L~(K)=i=1∑n[gifK(xi)+21hifK2(xi)]+Ω(fK)
定义一棵树
(4) 如何定义一棵树:
为了说明如何定义一棵树的问题,我们需要定义几个概念:
第一个概念是样本所在的节点位置 q ( x ) q(x) q(x),
第二个概念是有哪些样本落在节点j上 I j = { i ∣ q ( x i ) = j } I_{j}=\left\{i \mid q\left(\mathbf{x}_{i}\right)=j\right\} Ij={i∣q(xi)=j},
第三个概念是每个结点的预测值 w q ( x ) w_{q(x)} wq(x),
第四个概念是模型复杂度 Ω ( f K ) \Omega\left(f_{K}\right) Ω(fK),它可以由叶子节点的个数以及节点函数值来构建,则: Ω ( f K ) = γ T + 1 2 λ ∑ j = 1 T w j 2 \Omega\left(f_{K}\right) = \gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{j}^{2} Ω(fK)=γT+21λ∑j=1Twj2。
L
~
(
K
)
=
∑
i
=
1
n
[
g
i
f
K
(
x
i
)
+
1
2
h
i
f
K
2
(
x
i
)
]
+
γ
T
+
1
2
λ
∑
j
=
1
T
w
j
2
=
∑
j
=
1
T
[
(
∑
i
∈
I
j
g
i
)
w
j
+
1
2
(
∑
i
∈
I
j
h
i
+
λ
)
w
j
2
]
+
γ
T
\begin{aligned} \tilde{\mathcal{L}}^{(K)} &=\sum_{i=1}^{n}\left[g_{i} f_{K}\left(\mathrm{x}_{i}\right)+\frac{1}{2} h_{i} f_{K}^{2}\left(\mathrm{x}_{i}\right)\right]+\gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{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}+\lambda\right) w_{j}^{2}\right]+\gamma T \end{aligned}
L~(K)=i=1∑n[gifK(xi)+21hifK2(xi)]+γT+21λj=1∑Twj2=j=1∑T⎣⎡⎝⎛i∈Ij∑gi⎠⎞wj+21⎝⎛i∈Ij∑hi+λ⎠⎞wj2⎦⎤+γT
由于我们的目标就是最小化目标函数,现在的目标函数化简为一个关于w的二次函数:
L ~ ( K ) = ∑ j = 1 T [ ( ∑ i ∈ I j g i ) w j + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T \tilde{\mathcal{L}}^{(K)}=\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 L~(K)=∑j=1T[(∑i∈Ijgi)wj+21(∑i∈Ijhi+λ)wj2]+γT,
根据二次函数求极值的公式:
y
=
a
x
2
b
x
c
y=ax^2 bx c
y=ax2bxc求极值,对称轴在
x
=
−
b
2
a
x=-\frac{b}{2 a}
x=−2ab,极值为
y
=
4
a
c
−
b
2
4
a
y=\frac{4 a c-b^{2}}{4 a}
y=4a4ac−b2,因此:
w
j
∗
=
−
∑
i
∈
I
j
g
i
∑
i
∈
I
j
h
i
+
λ
w_{j}^{*}=-\frac{\sum_{i \in I_{j}} g_{i}}{\sum_{i \in I_{j}} h_{i}+\lambda}
wj∗=−∑i∈Ijhi+λ∑i∈Ijgi
以及
L
~
(
K
)
(
q
)
=
−
1
2
∑
j
=
1
T
(
∑
i
∈
I
j
g
i
)
2
∑
i
∈
I
j
h
i
+
λ
+
γ
T
\tilde{\mathcal{L}}^{(K)}(q)=-\frac{1}{2} \sum_{j=1}^{T} \frac{\left(\sum_{i \in I_{j}} g_{i}\right)^{2}}{\sum_{i \in I_{j}} h_{i}+\lambda}+\gamma T
L~(K)(q)=−21j=1∑T∑i∈Ijhi+λ(∑i∈Ijgi)2+γT
如何寻找树的形状
(5) 如何寻找树的形状:
不难发现,刚刚的讨论都是基于树的形状已经确定了计算
w
w
w和
L
L
L,但是实际上我们需要像学习决策树一样找到树的形状。因此,我们借助决策树学习的方式,使用目标函数的变化来作为分裂节点的标准。
L split = 1 2 [ ( ∑ i ∈ I L g i ) 2 ∑ i ∈ I L h i + λ + ( ∑ i ∈ I R g i ) 2 ∑ i ∈ I R h i + λ − ( ∑ i ∈ I g i ) 2 ∑ i ∈ I h i + λ ] − γ \mathcal{L}_{\text {split }}=\frac{1}{2}\left[\frac{\left(\sum_{i \in I_{L}} g_{i}\right)^{2}}{\sum_{i \in I_{L}} h_{i}+\lambda}+\frac{\left(\sum_{i \in I_{R}} g_{i}\right)^{2}}{\sum_{i \in I_{R}} h_{i}+\lambda}-\frac{\left(\sum_{i \in I} g_{i}\right)^{2}}{\sum_{i \in I} h_{i}+\lambda}\right]-\gamma Lsplit =21[∑i∈ILhi+λ(∑i∈ILgi)2+∑i∈IRhi+λ(∑i∈IRgi)2−∑i∈Ihi+λ(∑i∈Igi)2]−γ
如何找到最优节点分裂
(6)如何找到最优节点分裂
(6.1) 精确贪心分裂算法:
XGBoost在生成新树的过程中,最基本的操作是节点分裂。节点分裂中最重 要的环节是找到最优特征及最优切分点, 然后将叶子节点按照最优特征和最优切 分点进行分裂。
选取最优特征和最优切分点的一种思路如下:首先找到所有的候 选特征及所有的候选切分点, 一一求得其 L split \mathcal{L}_{\text {split }} Lsplit , 然后选择 L s p l i t \mathcal{L}_{\mathrm{split}} Lsplit 最大的特征及对应切分点作为最优特征和最优切分点。我们称此种方法为精确贪心算法。
该算法是一种启发式算法, 因为在节点分裂时只选择当前最优的分裂策略, 而非全局最优的分裂策略。精确贪心算法的计算过程如下所示:
(6.2) 基于直方图的近似算法:
精确贪心算法在选择最优特征和最优切分点时是一种十分有效的方法。它计算了所有特征、所有切分点的收益, 并从中选择了最优的, 从而保证模型能比较好地拟合了训练数据。但是当数据不能完全加载到内存时,精确贪心算法会变得 非常低效,算法在计算过程中需要不断在内存与磁盘之间进行数据交换,这是个非常耗时的过程, 并且在分布式环境中面临同样的问题。
为了能够更高效地选 择最优特征及切分点, XGBoost提出一种近似算法来解决该问题。 基于直方图的近似算法的主要思想是:对某一特征寻找最优切分点时,首先对该特征的所有切分点按分位数 (如百分位) 分桶, 得到一个候选切分点集。特征的每一个切分点都可以分到对应的分桶; 然后,对每个桶计算特征统计G和H得到直方图, G为该桶内所有样本一阶特征统计g之和, H为该桶内所有样本二阶特征统计h之和; 最后,选择所有候选特征及候选切分点中对应桶的特征统计收益最大的作为最优特征及最优切分点。基于直方图的近似算法的计算过程如下所示:
(6.3) 类似精确贪心算法,依据梯度统计找到最大增益的候选切分点。
示例
Treebooster
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234565) # 数据集分割
# 算法参数
params = {
'booster': 'gbtree',
'objective': 'multi:softmax',
'num_class': 3,
'gamma': 0.1,
'max_depth': 6,
'lambda': 2,
'subsample': 0.7,
'colsample_bytree': 0.75,
'min_child_weight': 3,
'silent': 0,
'eta': 0.1,
'seed': 1,
'nthread': 4,
}
#
Tree Booster的参数:
eta(learning_rate):learning_rate,在更新中使用步长收缩以防止过度拟合,默认= 0.3,范围:[0,1];典型值一般设置为:0.01-0.2
gamma(min_split_loss):默认= 0,分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,但性能就不一定能保证,需要平衡。范围:[0,∞]
max_depth:默认= 6,一棵树的最大深度。增加此值将使模型更复杂,并且更可能过度拟合。范围:[0,∞]
min_child_weight:默认值= 1,如果新分裂的节点的样本权重和小于min_child_weight则停止分裂 。这个可以用来减少过拟合,但是也不能太高,会导致欠拟合。范围:[0,∞]
max_delta_step:默认= 0,允许每个叶子输出的最大增量步长。如果将该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但是当类极度不平衡时,它可能有助于逻辑回归。将其设置为1-10的值可能有助于控制更新。范围:[0,∞]
subsample:默认值= 1,构建每棵树对样本的采样率,如果设置成0.5,XGBoost会随机选择一半的样本作为训练集。范围:(0,1]
sampling_method:默认= uniform,用于对训练实例进行采样的方法。
uniform:每个训练实例的选择概率均等。通常将subsample> = 0.5 设置 为良好的效果。
gradient_based:每个训练实例的选择概率与规则化的梯度绝对值成正比,具体来说就是 𝑔2+𝜆ℎ2⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯√ ,subsample可以设置为低至0.1,而不会损失模型精度。
colsample_bytree:默认= 1,列采样率,也就是特征采样率。范围为(0,1]
lambda(reg_lambda):默认=1,L2正则化权重项。增加此值将使模型更加保守。
alpha(reg_alpha):默认= 0,权重的L1正则化项。增加此值将使模型更加保守。
tree_method:默认=auto,XGBoost中使用的树构建算法。
auto:使用启发式选择最快的方法。
对于小型数据集,exact将使用精确贪婪()。
对于较大的数据集,approx将选择近似算法()。它建议尝试hist,gpu_hist,用大量的数据可能更高的性能。(gpu_hist)支持。external memory外部存储器。
exact:精确的贪婪算法。枚举所有拆分的候选点。
approx:使用分位数和梯度直方图的近似贪婪算法。
hist:更快的直方图优化的近似贪婪算法。(LightGBM也是使用直方图算法)
gpu_hist:GPU hist算法的实现。
scale_pos_weight:控制正负权重的平衡,这对于不平衡的类别很有用。Kaggle竞赛一般设置sum(negative instances) / sum(positive instances),在类别高度不平衡的情况下,将参数设置大于0,可以加快收敛。
num_parallel_tree:默认=1,每次迭代期间构造的并行树的数量。此选项用于支持增强型随机森林。
monotone_constraints:可变单调性的约束,在某些情况下,如果有非常强烈的先验信念认为真实的关系具有一定的质量,则可以使用约束条件来提高模型的预测性能。(例如params_constrained['monotone_constraints'] = "(1,-1)",(1,-1)我们告诉XGBoost对第一个预测变量施加增加的约束,对第二个预测变量施加减小的约束。)
plst=list(params.items())
dtrain=xgb.DMatrix(X_train,y_train)
num_rounds=500
model=xgb.train(plst,dtrain,num_rounds)
dtest=xgb.DMatrix(X_test)
y_pred=model.predict(dtest)
accuracy=accuracy_score(y_test,y_pred)
print('accuracy: %.2f%%'%(accuracy*100.0))
plot_importance(model)
plt.show()
Linear Booster
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error
# 加载数据集
boston = load_boston()
X,y = boston.data,boston.target
# XGBoost训练过程
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
params = {
'booster': 'gbtree',
'objective': 'reg:squarederror',
'gamma': 0.1,
'max_depth': 5,
'lambda': 3,
'subsample': 0.7,
'colsample_bytree': 0.7,
'min_child_weight': 3,
'silent': 1,
'eta': 0.1,
'seed': 1000,
'nthread': 4,
}
dtrain = xgb.DMatrix(X_train, y_train)
num_rounds = 300
plst = list(params.items())
model = xgb.train(plst, dtrain, num_rounds)
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
ans = model.predict(dtest)
# 显示重要特征
plot_importance(model)
plt.show()
LightBGM
略,reference: https://lightgbm.readthedocs.io/en/latest/Features.html