一、XGBoost算法
1.1 原理
- XGBoost的本质是GBDT,但是在速度和效率上发挥极致,XGBoost是一个优化的分布式梯度增强库,在GradientBoosting框架下实现机器学习算法
- XGBoost提供并行树提升(GBDT,GBM),可以快速准确地解决数据科学问题
- XGBoost以CART决策树为子模型,通过Gradient Tree Boosting实现多颗CART树的集成学习,得到最终模型。
模型构建:
数据为:
D
=
{
(
x
i
,
y
i
)
}
(
∣
D
∣
=
n
,
x
i
∈
R
m
,
y
i
∈
R
)
D=\{(x_i,y_i)\}(|D|=n ,x_i \in R^m,y_i \in R)
D={(xi,yi)}(∣D∣=n,xi∈Rm,yi∈R)
(1)构建目标函数:
假设有k棵树,则第i个样本的输出为
y
^
i
=
ϕ
(
x
i
)
=
∑
k
=
1
K
f
k
(
x
i
)
,
f
k
∈
F
,
其
中
,
F
=
{
f
(
x
)
=
w
q
(
x
)
}
(
q
:
R
m
→
T
,
w
∈
R
T
)
\hat{y}_i = \phi (x_i) = \sum_{k=1}^Kf_k(x_i),f_k \in \mathcal{F},其中,\\ \mathcal{F} = \{f(x) = w_{q(x)}\}(q:R^m \rightarrow T,w\in R^T )
y^i=ϕ(xi)=k=1∑Kfk(xi),fk∈F,其中,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(\hat{y}_i,y_i)+\sum_k \Omega (f_k)
L(ϕ)=i∑l(y^i,yi)+k∑Ω(fk)
其中,
∑
i
l
(
y
^
i
,
y
i
)
\sum_il(\hat{y}_i,y_i)
∑il(y^i,yi)为损失函数,
∑
k
Ω
(
f
k
)
\sum_k\Omega(f_k)
∑kΩ(fk)为正则化项
(2)叠加式的训练
给定样本
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 (y_i,\hat{y}_i^{(K-1)}+f_K(x_i))+\sum_{k}\Omega(f_k)
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 \bigg(y_i,\hat{y}_i^{(K-1)}+f_K(x_i)\bigg)+\sum_{k=1}^{K-1} \Omega(f_k) + \Omega(f_K)
L(k)=i=1∑nl(yi,y^i(K−1)+fK(xi))+k=1∑K−1Ω(fk)+Ω(fK),由于
∑
k
=
1
K
−
1
Ω
(
f
k
)
\sum_{k=1}^{K-1}\Omega(f_k)
∑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 \bigg(y_i,\hat{y}_i^{(K-1)}+f_K(x_i)\bigg)+\Omega (f_K)
L(K)=i=1∑nl(yi,y^i(K−1)+fK(xi))+Ω(fK)
(3)使用泰勒级数近似目标函数
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 \bigg[l\big(y_i,\hat{y}^{(K-1)}\big)+g_if_K(x_i)+\frac{1}{2}h_if^2_K(x_i)\bigg]+\Omega(f_K)
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\big(y_i,\hat{y}^{(t-1)}\big)
gi=∂y^(t−1)l(yi,y^(t−1))和
h
i
=
∂
y
^
(
t
−
1
)
2
l
(
y
i
,
y
^
(
t
−
1
)
)
h_i=\partial^2_{\hat{y}(t-1)}l\big(y_i,\hat{y}^{(t-1)}\big)
hi=∂y^(t−1)2l(yi,y^(t−1))
由于
∑
i
=
1
n
l
(
y
i
,
y
^
K
−
1
)
\sum_{i=1}^nl\big(y_i,\hat{y}^{K-1}\big)
∑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\bigg[g_if_K(x_i)+\frac{1}{2}h_if^2_K(x_i)\bigg]+\Omega(f_K)
L~(K)=i=1∑n[gifK(xi)+21hifK2(xi)]+Ω(fK)
(泰勒级数补充知识:https://www.zhihu.com/question/21149770/answer/111173412)
(4)如何定义一棵树
q ( x 1 ) = 1 , q ( x 2 ) = 3 , q ( x 3 ) = 1 , q ( x 4 ) = 2 , q ( x 5 ) = 3 , I 1 = { 1 , 3 } , I 2 = { 4 } , I 3 = { 2 , 5 } , w = { 15 , 12 , 20 } q(x_1) = 1,q(x_2)=3,q(x_3)=1,q(x_4)=2,q(x_5)=3,\\ I_1=\{1,3\},I_2=\{4\},I_3=\{2,5\},\\ w=\{15,12,20\} q(x1)=1,q(x2)=3,q(x3)=1,q(x4)=2,q(x5)=3,I1={1,3},I2={4},I3={2,5},w={15,12,20}
- 概念1:样本所在的节点位置 q ( x ) q(x) q(x)
- 概念2:哪些样本落在节点j上 I j = { i ∣ q ( x i ) = j } I_j=\{i|q(x_i)=j\} Ij={i∣q(xi)=j}
- 概念3:每个节点的预测值 w q ( x ) w_{q(x)} wq(x)
- 概念4:模型复杂度
Ω
(
f
K
)
\Omega(f_K)
Ω(fK),由叶子节点的个数以及节点函数值来构建,
Ω
(
f
K
)
=
γ
T
+
1
2
λ
∑
j
=
1
T
w
j
2
\Omega(f_K)=\gamma T+\frac{1}{2}\lambda \sum_{j=1}^Tw_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\bigg[g_if_K(x_i)+\frac{1}{2}h_if^2_K(x_i)\bigg]+\gamma T+\frac{1}{2}\lambda \sum_{j=1}^Tw_j^2 \\ &=\sum_{j=1}^T\bigg[\big(\sum_{i \in I_j}g_i\big)w_j+\frac{1}{2}\big(\sum_{i \in I_j}h_i+\lambda\big)w_j^2\bigg]+\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
根据二次函数求极值的公式, y = a x 2 + b x + c y=ax^2+bx+c y=ax2+bx+c在 x = − b 2 a x=-\frac{b}{2a} x=−2ab时,存在极值 y = 4 a c − b 2 4 a y = \frac{4ac-b^2}{4a} 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_jh_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{(\sum_{i \in I_j}g_i)^2}{\sum_{i \in I_j}h_i+\lambda}+\lambda T L~(K)(q)=−21j=1∑T∑i∈Ijhi+λ(∑i∈Ijgi)2+λT
(5)如何寻找树的形状
上面的讨论是基于树的形状已经确定了之后计算的
w
和
L
w和L
w和L,但是实际中需要像学习决策树一样找到树的形状。借助决策树学习的方法,使用目标函数的变化来作为分裂节点的标准。
例子中有8个样本,按照上面的分裂方式,
L
~
(
o
l
d
)
=
−
1
2
[
(
g
7
+
g
8
)
2
H
7
+
H
8
+
λ
+
(
g
1
+
…
+
g
6
)
2
H
1
+
…
+
H
6
+
λ
]
+
2
γ
L
~
(
n
e
w
)
=
−
1
2
[
(
g
7
+
g
8
)
2
H
7
+
H
8
+
λ
+
(
g
1
+
…
+
g
3
)
2
H
1
+
…
+
H
3
+
λ
+
(
g
4
+
…
+
g
6
)
2
H
4
+
…
+
H
6
+
λ
]
+
3
γ
L
~
(
o
l
d
)
−
L
~
(
n
e
w
)
=
1
2
[
(
g
1
+
…
+
g
3
)
2
H
1
+
…
+
H
3
+
λ
+
(
g
4
+
…
+
g
6
)
2
H
4
+
…
+
H
6
+
λ
−
(
g
1
+
…
+
g
6
)
2
H
1
+
…
+
H
6
+
λ
]
−
γ
\begin{aligned} \tilde{\mathcal{L}}^{(old)}= -\frac{1}{2} \big[ \frac{(g_7+g_8)^2}{H_7+H_8+\lambda} +\frac{(g_1+…+g_6)^2}{H1+…+H6+\lambda} \big] +2\gamma \\ \tilde{\mathcal{L}}^{(new)}= -\frac{1}{2} \big[ \frac{(g_7+g_8)^2}{H_7+H_8+\lambda} +\frac{(g_1+…+g_3)^2}{H1+…+H3+\lambda} +\frac{(g_4+…+g_6)^2}{H4+…+H6+\lambda} \big] +3\gamma\\ \tilde{\mathcal{L}}^{(old)}-\tilde{\mathcal{L}}^{(new)} = \frac{1}{2}\big[ \frac{(g_1+…+g_3)^2}{H1+…+H3+\lambda} +\frac{(g_4+…+g_6)^2}{H4+…+H6+\lambda} -\frac{(g_1+…+g_6)^2}{H1+…+H6+\lambda} \big]-\gamma \end{aligned}
L~(old)=−21[H7+H8+λ(g7+g8)2+H1+…+H6+λ(g1+…+g6)2]+2γL~(new)=−21[H7+H8+λ(g7+g8)2+H1+…+H3+λ(g1+…+g3)2+H4+…+H6+λ(g4+…+g6)2]+3γL~(old)−L~(new)=21[H1+…+H3+λ(g1+…+g3)2+H4+…+H6+λ(g4+…+g6)2−H1+…+H6+λ(g1+…+g6)2]−γ
分割点的标准为
max
{
L
~
(
o
l
d
)
−
L
~
(
n
e
w
)
}
\max\{\tilde{L}^{(old)}-\tilde{L}^{(new)}\}
max{L~(old)−L~(new)},即:
$$\mathcal{L}{split} = \frac{1}{2}\Big[\frac{\big(\sum{i \in I_L} g_{i}\big)^2}{\sum_{i \in I_L}h_i+\lambda}
- \frac{\big(\sum_{i \in I_R} g_i\big)^2}{\sum_{i \in I_R}h_i+\lambda}
- \frac{\big(\sum_{i \in I} g_i\big)^2}{\sum_{i \in I}h_i+\lambda}
\Big] -\lambda $$
(6) 找到分裂节点
(6.1) 精确贪心分裂算法
XGBoost在生成新树的过程中,最基本的操作是节点分裂。节点分裂中最重要的环节是找到最优特征及最优切分点,然后将叶子节点按照最优特征及最优切分点进行分裂。
选取最优特征和最优分点的一种思路:
- 先找到所有候选特征及所有的候选切分点,一一求出其 L s p l i t \mathcal{L}_{split} Lsplit
- 选择
L
s
p
l
i
t
\mathcal{L}_{split}
Lsplit的最大特征及对应切分点作为最优特征和最优切分点
该算法是一种启发式算法,因为在节点分裂时只选择当前最优的分裂策略,而非全局最优的分裂策略
精确贪心算法: - 输入:当前节点的样本集 I I I,特征维度 d d d
- 输出:最优分裂
1). 初始化分裂收益和梯度统计
g a i n = 0 , G = ∑ i ∈ I g i , H = ∑ i ∈ I h i gain=0,G=\sum_{i \in I}g_i,H=\sum_{i \in I}h_i gain=0,G=i∈I∑gi,H=i∈I∑hi
2). 对每个特征k=1,2,…,m,执行以下步骤: - 初始化左子节点的一阶梯度统计和二阶梯度统计。
G L = 0 , H L = 0 G_L =0,H_L=0 GL=0,HL=0 - 对节点包含的所有样本在该特征下的取值进行排序,然后遍历每个取值j
- 计算左子节点和右子节点的梯度统计
G L = G L + g j , H L = H L + h j G R = G − G L , H R = H − H L G_L =G_L+g_j,H_L=H_L+h_j \\ G_R = G-G_L,H_R=H-H_L GL=GL+gj,HL=HL+hjGR=G−GL,HR=H−HL - 计算最终分裂后收益,选择收益最大的。
g a i n = m a x ( g a i n , G L 2 H L + λ + G R 2 H R + λ − G 2 H + λ ) gain = max\Big(gain, \frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{G^2}{H+\lambda} \Big) gain=max(gain,HL+λGL2+HR+λGR2−H+λG2)
3). 按照最大收益的特征及其分裂点进行分裂。
- 计算左子节点和右子节点的梯度统计
(6.2) 基于直方图的近似算法
-
精确贪心算法在选择最优特征和最优切分点时是一种十分有效的方法。计算了所有特征和切分点的收益,并从中选择了最优,从而保证模型较好的拟合训练数据。但是当数据不能完全加载到内存时,精确贪心算法变得非常低效。基于直方图的近似算法解决上面的问题。
-
基于直方图的近似算法的思想:
- 对某一特征寻找最优切分点时,首先对该特征的所有切分点按分位数(如百分数)分桶,得到一个候选切分点集。
- 特征的每一个切分点都可以分到对应的分桶,然后对每个桶计算特征统计G和H得到直方图,G为该桶内所有样本一阶特征g之后,H为该桶内所有样本二阶特征统计h之和
- 最后,选择所有候选特征及候选切分点中对应桶的特征,统计收益最大的作为最优特征及最优切分点。
-
基于直方图的近似算法的计算过程:
- 1). 对于每个特征 k = 1 , 2 , … , m k=1,2,…,m k=1,2,…,m,按照分位数对特征k分桶 Θ \Theta Θ,可得候选切分点, S k = { S k 1 , S k 2 , … , S k l } 1 S_k = \{S_{k1}, S_{k2},…,S_{kl}\}^1 Sk={Sk1,Sk2,…,Skl}1
- 2). 对于每个特征
k
=
1
,
2
,
…
,
m
k=1,2,…,m
k=1,2,…,m,有:
G k v ← = ∑ j ∈ { j ∣ s k , v ≥ x j k > s k , v − 1 } g j H k v ← = ∑ j ∈ { j ∣ s k , v ≥ x j k > s k , v − 1 } h j \begin{array}{l} G_{k v} \leftarrow=\sum_{j \in\left\{j \mid s_{k, v} \geq \mathbf{x}_{j k}>s_{k, v-1\;}\right\}} g_{j} \\ H_{k v} \leftarrow=\sum_{j \in\left\{j \mid s_{k, v} \geq \mathbf{x}_{j k}>s_{k, v-1\;}\right\}} h_{j} \end{array} Gkv←=∑j∈{j∣sk,v≥xjk>sk,v−1}gjHkv←=∑j∈{j∣sk,v≥xjk>sk,v−1}hj - 3). 类似精确贪心算法,依据梯度统计找到最大增益得候选切分点。
假设有一个年龄特征,其特征的取值为18、19、21、31、36、37、55、57,我们需要使用近似算法找到年龄这个特征的最佳分裂点:
-
近似算法实现了两种候选切分点的构建策略:全局策略和本地策略
-
全局策略是在树构建的初始阶段对每一个特征确定一个候选切分点的集合,并在该树每一层的节点分类中均采用此集合计算收益,整个过程候选切分点集合不改变
-
本地策略是在每一次节点分裂时均重新确定候选切分点
-
全局策略需要更细的分桶才能达到本地策略的精确度
-
全局策略在选取候选切分点集合时比本地策略简单
-
在XGBoost中,精确贪心算法、近似算法全局策略、近似算法本地策略,均可以通过参数进行配置
1.2 实现
# XGBoost原生工具库的上手
import xgboost as xgb
#读取数据
dtrain = xgb.DMatrix('demo/data/agaricus.txt.train')
#XGBoost的专属数据格式,也可以使用dataframe和ndarray
dtest = xgb.DMatrix('demo/data/agaricus.txt.test')
param = {'max_depth':2, 'eta':1, 'objective':'binary:logistic'}
num_round = 2 #使用线程数
bst = xgb.train(param, dtrain, num_round) #训练
#预测
preds = bst.predict(dtest)
参考:https://xgboost.readthedocs.io/en/latest/index.html
1.2.1 XGBoost的参数:
1. 通用参数(两种类型的booster,tree的性能比线性回归好得多,一般使用tree)
- booster:弱学习器。默认:gbtree,可选:gbtree,gblinear,dart
- nthread:运行XGBoost得并行线程数,默认为最大可用线程数
- verbosity:打印消息的详细程度。0:静默;1:警告;2:信息;3:调试
1) Tree Booster的参数: - eta(learning_rate):默认0.3,典型值一般设置0.01-0.2
- gamma(min_split_loss):默认0,分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,性能不一定能保证
- max_depth:默认6,一棵树的最大深度。增加此值使模型更复杂,更可能过拟合
- min_child_weight:默认1,新分裂的节点的样本权重和小于该值则停止分裂。用来减少过拟合,不能太高,会导致欠拟合
- max_delta_step:默认0,允许每个叶子输出的最大增量步长。为0时表示没有约束,正值可以使更新步骤更保守。通常不设置,当类极度不平衡时,有助于逻辑回归。一般设置在1-10
- subsample:默认1,构建每棵树对样本的采样率,如果为0.5,XGBoost会随机选择一半的样本作为训练集
- sampling_method:默认uniform。uniform:每个训练实例选择概率均等,通常将subsample>=0.5设置为良好的效果;gradient_based:每个训练实例的选择概率与规则化的梯度绝对值成正比, g 2 + λ h 2 \sqrt{g^2+\lambda h^2} g2+λh2,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:更快的直方图优化的近似贪婪算法(LightGBM使用直方图算法)
- gpu_hist:GPU hist算法的实现
- auto:使用启发式选择最快的方法:
- scale_pos_weight:控制正负权重的平衡。Kaggle竞赛一般设置sum(negative instances)/sum(positive instances),在类别高度不平衡的情况下,将参数设置大于0,可以加快收敛
- num_parallel_tree:默认1,每次迭代期间构造的并行树的数量,用于支持增强型随机森林
- monotone_constraints:可变单调性的约束,在某些情况下,有强烈的先验信念认为真实的关系具有一定的质量,可以使用约束条件来提高模型的预测性能
2) Linear Booster的参数:
- lambda(reg_lambda):默认0,L2正则化权重项。归一化为训练示例数
- alpha(reg_lambda)
- updater:默认shotgun
- shotgun:基于shotgun孙发的平行坐标下降算法。使用hogwild并行性,每次运行都产生不确定的解决方案
- coord_descent:普通坐标下降算法。多线程的,会产生确定性的解决方案
- feature_selector:默认cyclic。特征选择和排序方法
- cyclic:通过每次循环一个特征来实现
- shuffle:类似cyclic。但每次更新之前都有随机的特征变换
- random:一个随机(有放回)特征选择器
- greedy:选择梯度最大的特征(贪婪选择)
- thrifty:近似贪婪特征选择(近似greedy)
- top_k:要选择的最重要特征数(在greedy和thrift之内)
2. 任务参数(控制理想的优化目标和每一步结果的度量方法)
- objective:默认reg:squarederror
- reg:squarederror:最小平方误差
- reg:squaredlogerror:对数平方损失 1 2 [ l o g ( p r e d + 1 ) − l o g ( l a b e l + 1 ) ] 2 \frac{1}{2}[log(pred+1)-log(label+1)]^2 21[log(pred+1)−log(label+1)]2
- reg:logistic:逻辑回归
- reg:pseudohubererror:伪Huber损失进行回归,是绝对损失的两倍可微选择
- binary:logistic:二元分类的逻辑回归,输出概率
- binary:logitraw:二进制分类逻辑回归,逻辑转换之前的输出得分
- binary:hinge:二进制分类的铰链损失。使预测为0或1,而不是产生概率(SVM是铰链损失函数)
- count:poisson:计数数据的泊松回归,泊松分布的输出平均值
- survival:cox:针对正确的生存时间数据进行Cox回归(负值视为正确的生存时间)
- survival:aft:检查生存时间数据的加速故障时间模型
- sft_loss_distribution:survival:aft和aft-nloglik度量标准使用的概率密度函数
- multi:softmax:设置XGBoost以使用softmax目标进行多类分类,还可以设置num_class(类数)
- multi:softprob:与softmax相同,但输出向量,可以进一步重整为矩阵。结果包含属于每个类别的每个数据点的预测概率
- rank:pairwise:使用LambdaMART进行成对排名,使成对损失最小化
- rank:ndcg:使用LambdaMART进行列表式排名,使标准化折让累计收益(NDCG)最大化
- rank:map:使用LambdaMART进行列表平均排名,使平均精度(MAP)最大化
- reg:gamma:使用对数链接进行伽马回归,输出伽马分布的平均值
- reg:tweedie:使用对数链接进行Tweedie回归
- eval_metric:验证数据的评估指标,将根据目标分配默认指标,可以添加多个评估指标
- rmse:均方根误差
- rmsle:均方根对数误差
- mae:平均绝对误差
- mphe:平均伪Huber错误
- logloss:负对数似然
- error:二进制分类错误率
- merror:多类分类错误率
- mlogloss:多类logloss
- auc:曲线下面积
- aucpr:PR曲线下的面积
- ndcg:归一累计折扣
- map:平均精度
- seed:随机数种子
1.2.2 XGBoost的调参说明
参数调优的一般步骤:
- 确定学习速率和提升参数调优的初始值
- max_depth和min_child_weight参数调优
- gamma参数调优
- subsample和colsample_bytree参数调优
- 正则化参数alpha调优
- 降低学习速率和使用更多的决策树
1.2.3 XGBoost使用
(1)数据接口(可以的处理格式)
# 1. LibSVM文本格式
dtrain = xgb.DMatrix('train.svm.txt')
dtest = xgb.DMatrix('test.svm.buffer')
# 2. CSV文件(不能含类别文本变量,若存在文本变量需要做特征处理,如one-hot)
dtrain = xgb.DMatrix('train.csv?format=csv&label_column=0')
dtest = xgb.DMatrix('test.csv?format=csv&label_column=0')
# 3. Numpy数组
data = np.random.rand(5, 10)
label = np.random.randint(2, size=5)
dtrain = xgb.DMatrix(data=data, label=label)
# 4. scipy.sparse数组
csr = scipy.sparse.csr_matrix((dat, (row, col)))
dtrain = xgb.DMatrix(csr)
# 5. pandas数据框DataFrame
data = pandas.DataFrame(np.arange(12).reshape((4,3)), columns=['a','b','c'])
label = pandas.DataFrame(np.random.randint(2,size=4))
dtrain = xgb.DMatrix(data, label=label)
推荐先保存到XGBoost二进制文件中使加载速度更快,然后再加载进来
# 1. 保存DMatrix到XGBoost二进制文件中
dtrain = xgb.DMatrix('train.svm.txt')
dtrain.save_binary('train.buffer')
# 2. 缺少的值可以用DMatrix构造函数中的默认值替换
dtrain = xgb.DMatrix(data, label=label, missing=999.0)
# 3. 需要时可设置权重
w = np.random.rand(5, 1)
dtrain = xgb.DMatrix(data, label=label, missing=999.0, weight=w)
(2) 参数的设置方式
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
#加载并处理数据
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data',header=None)
df_wine.columns = ['Class label', 'Alcohol','Malic acid', 'Ash','Alcalinity of ash','Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols','Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']
df_wine = df_wine[df_wine['Class label'] != 1]
X = df_wine[['Alcohol','OD280/OD315 of diluted wines']].values
y = df_wine['Class label'].values
le = LabelEncoder()
y = le.fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=1,stratify=y)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test)
# 1. Booster参数
params = {
'booster': 'gbtree',
'objective': 'multi:softmax', #多分类问题
'num_class':10, #类别数,与multisoftmax并用
'gamma':0.1, #控制是否后剪枝的参数
'max_depth':12,
'lambda':2, #控制模型复杂度的权重值的L2正则化参数,参数越大,越不容易过拟合
'subsample':0.7, #随机采样训练样本
'colsample_bytree':0.7, #生成树时进行的列采样
'min_child_weight':3,
'silent':1, #设置成1,则没有运行信息输出 ,最好设置为0
'eta':0.007,
'seed':1000,
'nthread':4, #cpu线程数
'eval_metric':'auc'
}
plst = list(params.items()) #注意需要变为list,否则会报错
# evallist = [(dtest,'eval'),('dtrain','train')] #指定验证集
# 2. 训练
num_round = 10
bst = xgb.train( plst, dtrain, num_round)
# 3. 保存模型
bst.save_model('0001.model')
bst.dump_model('dump.raw.txt')
# 4. 加载保存的模型
bst = xgb.Booster({'nthread':4})
bst.load_model('0001.model')
# 5. 设置早停机制
train(...,evals=evals, early_stopping_rounds=10)
# 6. 预测
ypred = bst.predict(dtest)
# 7. 绘制重要性特征图
# 绘制重要性
xgb.plot_importance(bst)
# 绘制输出树
# xgb.plot_tree(bst, num_trees=2)
# 使用xgboost.to_graphviz()将目标树转换为graphviz
# xgb.to_graphviz(bst, num_trees=2)
<AxesSubplot:title={'center':'Feature importance'}, xlabel='F score', ylabel='Features'>
1.3 XGBoost分类案例
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,
}
plst = list(params.items())
dtrain = xgb.DMatrix(X_train, y_train) # 生成数据集格式
num_rounds = 500
model = xgb.train(plst, dtrain, num_rounds) # xgboost模型训练
# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
y_pred = model.predict(dtest)
# 计算准确率
accuracy = accuracy_score(y_test,y_pred)
print("accuarcy: %.2f%%" % (accuracy*100.0))
# 显示重要特征
plot_importance(model)
plt.show()
1.4 XGBoost回归案例
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.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()
1.4 XGBoost调参(结合sklearn网格搜索)
import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import roc_auc_score
iris = load_iris()
X,y = iris.data,iris.target
col = iris.target_names
train_x, valid_x, train_y, valid_y = train_test_split(X, y, test_size=0.3, random_state=1) # 分训练集和验证集
parameters = {
'max_depth': [5, 10, 15, 20, 25],
'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15],
'n_estimators': [500, 1000, 2000, 3000, 5000],
'min_child_weight': [0, 2, 5, 10, 20],
'max_delta_step': [0, 0.2, 0.6, 1, 2],
'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9],
'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]
}
xlf = xgb.XGBClassifier(max_depth=10,
learning_rate=0.01,
n_estimators=2000,
silent=True,
objective='multi:softmax',
num_class=3 ,
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=0,
missing=None)
gs = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gs.fit(train_x, train_y)
print("Best score: %0.3f" % gs.best_score_)
print("Best parameters set: %s" % gs.best_params_ )
代码执行后:存在缺失值错误,问题待查找原因