赞
踩
XGBoost是陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中,并取得了不错的成绩。
XGBoost本质上是一个GBDT(Gradient Boosting Decision Tree,梯度提升决策树),GBDT使用了Boosting的思想,其基本原理是所有弱分类器的结果相加等于预测值,然后下一个弱分类器去拟合上一个预测的残差(这个残差就是预测值与真实值之间的误差)1。
相比GBDT,XGBoost在工程实现上做了大量的优化,力争把速度和效率发挥到极致,所以叫X(Extreme)GBoost。
假设我们要预测一家人对电子游戏的喜好程度,已知喜好程度打分真实值:男孩2.9,女孩-0.8,爷爷-1.9,奶奶-1.9,妈妈-0.1。考虑到年龄因素,年轻人更可能喜欢电子游戏;考虑到性别因素,男性更喜欢电子游戏,故先根据年龄大小区分小孩和大人,然后再通过性别区分是男是女,逐一给各人在电子游戏喜好程度上打分,训练出第一颗树,如下图所示。
接着再根据电脑使用频率进行分类打分,训练出第二颗树,如下图所示。
而我们最终的预测分数是将两棵树的预测值相加。例如,小男孩的分数是2+0.9=2.9,爷爷的分数是-1-0.9=-1.9。
这与GBDT的原理异曲同工,第二颗树对男孩的预测值是男孩的真实值与第一颗树预测值的差值(0.9=2.9-2),即残差,这正好对应了上文提到的“下一个弱分类器去拟合上一个预测的残差”。最终的预测结果是所有分类器的结果相加。
总而言之,XGBoost的核心算法思想基本就是:
XGBoost与GBDT比较大的不同就是目标函数的定义。在第t轮,我们需要寻找一个f,来最小化下面的目标函数:
O
b
j
(
t
)
=
∑
i
=
1
n
l
(
y
i
,
y
^
i
(
t
−
1
)
+
f
t
(
x
i
)
)
+
Ω
(
f
t
)
+
c
o
n
s
t
a
n
t
\boldsymbol{Obj^{(t)}=\sum_{i=1}^n l\Big(y_i, \hat{y}_i^{(t-1)}+f_t(x_i)\Big)+\Omega(f_t)+constant}
Obj(t)=i=1∑nl(yi,y^i(t−1)+ft(xi))+Ω(ft)+constant
其中第一项中的
l
(
)
l(\quad)
l()为损失函数;第二项为正则项,控制树的复杂度,防止过拟合;第三项为常数。在这个式子中,
y
^
i
(
t
−
1
)
+
f
t
(
x
i
)
=
y
^
i
(
t
)
\hat{y}_i^{(t-1)}+f_t(x_i)=\hat{y}_i^{(t)}
y^i(t−1)+ft(xi)=y^i(t),即第t轮的预测值,表示是由上一轮预测值加上本轮结果得到。
接下来,用泰勒展开三项来近似我们的目标函数:
O
b
j
(
t
)
≅
∑
i
=
1
n
[
l
(
y
i
,
y
^
i
(
t
−
1
)
)
+
g
i
f
t
(
x
i
)
+
1
2
h
i
f
t
2
(
x
i
)
]
+
Ω
(
f
t
)
+
c
o
n
s
t
a
n
t
\boldsymbol{Obj^{(t)}\cong\sum_{i=1}^n \Big[l(y_i, \hat{y}_i^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t^2(x_i)\Big]+\Omega(f_t)+constant}
Obj(t)≅i=1∑n[l(yi,y^i(t−1))+gift(xi)+21hift2(xi)]+Ω(ft)+constant
其中正则项
Ω
(
f
t
)
=
γ
T
+
1
2
λ
∑
j
=
1
T
w
j
2
\Omega(f_t)=\gamma T+\frac{1}{2}\lambda\sum_{j=1}^T w_j^2
Ω(ft)=γT+21λ∑j=1Twj2,
w
w
w是叶结点权重(分数),
T
T
T是叶结点个数。
接下来求解这个目标函数,最终化为:
O
b
j
(
t
)
=
∑
j
=
1
T
[
(
∑
i
∈
I
j
g
i
)
⋅
w
j
+
1
2
(
∑
i
∈
I
j
h
i
+
λ
)
⋅
w
j
2
]
+
γ
T
\boldsymbol{Obj^{(t)}=\sum_{j=1}^T\Big[(\sum_{i\in I_j} g_i)\cdot w_j+\frac{1}{2}(\sum_{i\in I_j} h_i+\lambda)\cdot w_j^2\Big]+\gamma T}
Obj(t)=j=1∑T[(i∈Ij∑gi)⋅wj+21(i∈Ij∑hi+λ)⋅wj2]+γT
其中
I
j
=
{
i
∣
q
(
x
i
)
=
j
}
I_j=\{i|q(x_i)=j\}
Ij={i∣q(xi)=j}代表映射到叶结点
j
j
j的样本
x
i
x_i
xi的所有下标,
q
q
q表示从样本到叶结点的映射(代表了树结构)。(推导过程不作赘述,参考# XGBoost原理)
最终我们将关于树模型的迭代转化为关于树的叶节点的迭代,并求出最优的叶节点分数,令
∂
O
b
j
(
t
)
/
∂
w
j
=
0
\partial Obj^{(t)}/\partial w_j=0
∂Obj(t)/∂wj=0,得
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
(
t
)
(
q
)
=
−
1
2
∑
j
=
1
T
(
∑
i
∈
I
j
g
i
)
2
∑
i
∈
I
j
h
i
+
λ
+
γ
T
\boldsymbol{L^{(t)}(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}+\gamma T}
L(t)(q)=−21j=1∑T∑i∈Ijhi+λ(∑i∈Ijgi)2+γT
我们的任务就是找到一个最好的树结构
q
q
q使得这个函数最小,得分越小,说明结构越好。
很显然,一棵树的生成是由一个节点一分为二,然后不断分裂最终形成为整棵树。对于一个叶子节点如何进行分裂,XGBoost做法是枚举所有不同树结构的贪心法。
不断地枚举不同树的结构,然后利用打分函数来寻找出一个最优结构的树,接着加入到模型中,不断重复这样的操作。这个寻找的过程使用的就是贪心算法。选择一个feature分裂,计算loss function最小值,然后再选一个feature分裂,又得到一个loss function最小值,枚举完,找一个效果最好的,把树给分裂,就得到了小树苗。
限于篇幅,更多的实现细节参考# XGBoost原理
XGBoost算法的实现以鸢尾花数据集为例。Iris鸢尾花数据集是一个经典数据集,在统计学习和机器学习领域都经常被用作示例。数据集内包含 3 类共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于(iris-setosa,iris-versicolour,iris-virginica)中的哪一品种3。部分数据截图如下:
下面的示例代码4采用直接调用xgboost包的方式。
#导入sklearn和xgboost包 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import xgboost as xgb #用于显示正确率 def show_accuracy(a, b, tip): acc = a.ravel() == b.ravel() print (acc) print (tip + '正确率:\t', float(acc.sum()) / a.size) if __name__ == "__main__": #加载iris数据集 data=load_iris() X=data.data Y=data.target #划分训练集和测试集 X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.25,random_state=1) #数据转换为数据矩阵类DMatrix data_train = xgb.DMatrix(X_train,label=y_train) data_test = xgb.DMatrix(X_test,label=y_test) #设置参数 param = {'max_depth': 3, 'eta': 1, 'silent': 1, 'objective': 'multi:softmax','num_class': 3} watchlist = [(data_test, 'eval'), (data_train, 'train')] #训练模型 bst = xgb.train(param, data_train, num_boost_round=4, evals=watchlist) #测试 y_hat = bst.predict(data_test) show_accuracy(y_hat, y_test, 'XGBoost ')
param各项参数的含义可参考4。
运行结果如下:
XGBoost的代码实现还可以使用xgboost包的sklearn接口xgboost.XGBClassifier(),利用函数参数设置模型参数,限于篇幅不再赘述,读者可以参考链接Github:XGBoost.ipynb。
XGBoost是一种GBDT的实现,是一个优秀的分类算法,相比GBDT有许多优势,如:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。