XGBoost 是 eXtreme Gradient Boosting 的缩写称呼,它是一个非常强大的 Boosting 算法工具包,优秀的性能(效果与速度)让其在很长一段时间内霸屏数据科学比赛解决方案榜首,现在很多大厂的机器学习方案依旧会首选这个模型。
XGBoost 在并行计算效率、缺失值处理、控制过拟合、预测泛化能力上都变现非常优秀。本文我们给大家详细展开介绍 XGBoost,包含「算法原理」和「工程实现」两个方面。
关于 XGBoost 的原理,其作者陈天奇本人有一个非常详尽的Slides做了系统性的介绍,我们在这里借助于这个资料给大家做展开讲解。
符号(Notations):��∈��xi∈Rd表示训练集中的第i个样本。
模型(Model):对于已知的��xi如何预测��^yi^?
线性模型(Linear Model):�^=∑������y^=∑jwjxij(包括线性回归和逻辑回归),预测值��^yi^根据不同的任务有不同的解释:
Ridge回归(L2正则化):
• Ridge 是线性模型(Linear Model),用的是平方损失(Square Loss),正则化项是 L2 Norm。
Lasso回归(L1正则化):
• Lasso是线性模型(Linear Model),用的是平方损失(Square Loss),正则化项是L1 Norm。
逻辑回归:
• 逻辑回归是线性模型(Linear Model),用的是逻辑损失(Logistic Loss),正则化项是 L2 Norm。
案例:
如上图所示,将左侧的数据输入到模型1中,会得到预测收入。预测收入和真实的收入之间的差值记做残差
。由于这个模型1有一定的能力,但是能力比较弱,遗留了一些问题。这个残差就能表征这个遗留的问题。
紧接着,再训练一个模型2去预测这些样本,只不过目标值改为刚刚得到的残差。上图所示,预测的结果不再是收入,而是模型1得到的残差。上图中的模型2还会得到残差,但是我们发现第一行样本的残差已经为零了。也就是说第一个样本,通过模型1和模型2能够预测对收入。但是除了第一行,其他的还是有残差的,这时候可以在这基础上训练一个模型3
上图所示,在刚刚 模型2得到的残差(准确的说是模型1和模型2共同作用的结果)
的基础上去拟合,得到模型3。这时候的残差可以理解为是前两个模型遗留下来的问题。该模型去预测模型2的残差,我们发现通过前三个模型的预测,得到的残差是上图中最新的残差这一列。
这时候最新的残差都是非常小了,如果能达到我们满意的标准,我们就可以停下。这样我们就得到了三个不同的模型。如下图所示,最终的预测就是三个模型预测的结果和。如下图:
我们解决问题的步骤:
如何构造目标函数 -> 目标函数直接优化难,如何近似? -> 如何把树的结构引入到目标函数?-> 仍然难优化,要不要使用贪心算法?
首先举个例子,用多棵树来预测张三、李四的薪资。如下图所示,用年龄这个因素构建的树预测张三的值为12,用工作年限这个因素构建的树张三为2. 两个相加就是对张三薪资的预测:12+2=14。
假设已经训练了�K颗树,则对于第�i个样本的最终预测值为:
��xi是样本的特征,��(��)fk(xi)是用第�k颗树��xi样本进行预测。将结果加在一起就得到了最终的预测值�^�y^i,而该样本的真实label是��yi。这样我们就能构建损失函数了。
构建的目标函数如下:
损失函数计算模型预测值和真实值的 loss,其中�l是损失函数,可以是 MSE、Cross Entropy 等等。第二项是正则项,来控制模型的复杂度,防止过拟合。这个正则项可以类比 L2 正则。
经过上面的一步步的简化,我们把最初的目标函数:
简化为了:
紧接着,看下图,假设第一个叶节点上(即 15 的地方)有样本[1, 3]落在这里 ,第二个节点有样本[2]落在这个地方,样本[4,5]落在了第三个叶子结点处这里 :
所以:
二次函数求最优解问题。
知识回顾,典型的二次函数:
最小点的值为:
。所以,使用贪心的方式,选择新的树目标函数值较小的那颗树。
比如下面这个例子,我们有样本[1、2、3、4、5、6、7、8],第一颗树把这些样本分为了两部分,左侧的叶子结点是
[7,8],右侧节点是[1,2,3,4,5,6]。
此时我们知道了树的结构,可以根据如下的公式计算出此时树的最小目标函数值:
紧接着,我们根据新的特征对叶子结点再次进行了分割,得到了如下的树的形状:
紧接着计算两颗树最小目标函数值的差:
XGBoost 将每一列特征提前进行排序,以块(Block)的形式储存在缓存中,并以索引将特征值和梯度统计量对应起来,每次节点分裂时会重复调用排好序的块。而且不同特征会分布在独立的块中,因此可以进行分布式或多线程的计算。
数据量非常大的情形下,无法同时全部载入内存。XGBoost 将数据分为多个 blocks 储存在硬盘中,使用一个独立的线程专门从磁盘中读取数据到内存中,实现计算和读取数据的同时进行。为了进一步提高磁盘读取数据性能,XGBoost 还使用了两种方法:
GBDT和这里的 XGBoost 做一个对比总结:
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
# 导入数据集
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)
model = xgb.XGBRegressor(max_depth=5,learning_rate=0.1,n_estimators=160,silent=True,objective='reg:gamma')
model.fit(X_train,y_train)
# 对测试集进行预测
ans = model.predict(X_test)
# 显示重要特征
plot_importance(model)
plt.show()
PythonCopy
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn.datasets import make_hastie_10_2
from xgboost.sklearn import XGBClassifier
X, y = make_hastie_10_2(random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)##test_size测试集合所占比例
clf = XGBClassifier(
silent=0 ,#设置成1则没有运行信息输出,最好是设置为0.是否在运行升级时打印消息。
#nthread=4,# cpu 线程数 默认最大
learning_rate= 0.3, # 如同学习率
min_child_weight=1,
# 这个参数默认是 1,是每个叶子里面 h 的和至少是多少,对正负样本不均衡时的 0-1 分类而言
#,假设 h 在 0.01 附近,min_child_weight 为 1 意味着叶子节点中最少需要包含 100 个样本。
#这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易 overfitting。
max_depth=6, # 构建树的深度,越大越容易过拟合
gamma=0, # 树的叶子节点上作进一步分区所需的最小损失减少,越大越保守,一般0.1、0.2这样子。
subsample=1, # 随机采样训练样本 训练实例的子采样比
max_delta_step=0,#最大增量步长,我们允许每个树的权重估计。
colsample_bytree=1, # 生成树时进行的列采样
reg_lambda=1, # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
#reg_alpha=0, # L1 正则项参数
#scale_pos_weight=1, #如果取值大于0的话,在类别样本不平衡的情况下有助于快速收敛。平衡正负权重
#objective= 'multi:softmax', #多分类的问题 指定学习任务和相应的学习目标
#num_class=10, # 类别数,多分类与 multisoftmax 并用
n_estimators=100, #树的个数
seed=1000 #随机种子
#eval_metric= 'auc'
)
clf.fit(X_train,y_train,eval_metric='auc')
#设置验证集合 verbose=False不打印过程
clf.fit(X_train, y_train,eval_set=[(X_train, y_train), (X_val, y_val)],eval_metric='auc',verbose=False)
#获取验证集合结果
evals_result = clf.evals_result()
y_true, y_pred = y_test, clf.predict(X_test)
print"Accuracy : %.4g" % metrics.accuracy_score(y_true, y_pred)
#回归
#m_regress = xgb.XGBRegressor(n_estimators=1000,seed=0)
PythonCopy
params = {'objective': 'reg:squarederror',
# 默认reg:linear。 reg:squarederror,代表要解决的问题时分类还是回归,取值可以很多,一般只关心是分类还是回归,
# 在回归问题objective一般使用reg:squarederror ,即MSE均方误差或者:reg:linear , reg:logistic , count:poisson 。
# 二分类问题一般使用binary:logistic,rank:pairwise
# 多分类问题一般使用multi:softmax
阅读量:2012
点赞量:0
收藏量:0