当前位置: 首页 > 后端技术 > Python

机器学习导论:拆解极速GBDT原理

时间:2023-03-26 19:20:55 Python

机器学习导论:拆解极速GBDT梯度提升Boosting是一种集成学习的基分类器(弱分类器)生成方法。其核心思想是通过迭代生成一系列学习器,对错误率低的学习器赋予高权重,对错误率高的学习器赋予低权重。权重,结合弱学习器和相应的权重来生成强学习器。Boosting算法包括两部分,加法模型和前向步进算法。加性模型是指强分类器由一系列弱分类器线性相加而成。一般组合形式如下:$$F_M(x;P)=\sum_{m=1}^n\beta_mh(x;a_m)$$其中,$h(x;a_m)$为弱分类器一个接一个,$a_m$是弱分类器学习到的最优参数,$β_m$是弱学习在强分类器中的比例,P是所有$α_m$和$β_m$的组合。这些弱分类器线性相加形成强分类器。前向步进是指在训练过程中,在上一轮迭代的基础上训练下一轮迭代生成的分类器。即可以写成这样的形式:$$F_m(x)=F_{m-1}(x)+\beta_mh_m(x;a_m)$$GradientBoosting=GradientDescent+BoostingBoosting算法(以AdaBoost为代表)错误通过划分数据点来识别问题,通过调整错误分类数据点的权重来改进模型。GradientBoosting使用负梯度来识别问题并计算负梯度来改进模型。GradientBoosting每次迭代的目标都是减少上次的残差,并在残差减少的梯度(Gradient)方向上建立新的模型。每一个新模型的建立都是为了让之前模型的残差往梯度的方向发展。减少。第t轮第i个样本的损失函数的负梯度为:$$\large{r_{mi}}=-\left[\frac{\partialL(y_i,f(x_i))}{\partialf(x_i)}\right]_{f(x)=f_{m-1}(x)}$$此时,不同的损失函数会得到不同的负梯度。如果选择平方损失$L(y_i,f(x_i))=\frac{1}{2}(y_i-f(x_i))^2$则负梯度为$r_{mi}=y_i-f(x_i)$此时我们发现GBDT的负梯度就是残差Poor,所以对于回归问题,我们要拟合的就是残差。GBDT回归算法的输入是训练集样本$T=\{(x_,y_1),(x_2,y_2),...(x_m,y_m)\}$,最大迭代次数T,以及损失函数L。输出为强学习器$f(x)$1)初始化弱学习器2)对于迭代次数t=1,2,...T:$f_0(x)=\underbrace{arg\;min}_{c}\sum\limits_{i=1}^{m}L(y_i,c)$a)对于样本$i=1,2,...m$,计算负梯度$$r_{ti}=-\bigg[\frac{\partialL(y_i,f(x_i)))}{\partialf(x_i)}\bigg]_{f(x)=f_{t-1}\;\;(x)}$$b)使用$(x_i,r_{ti})\;\;(i=1,2,..m)$拟合一棵CART回归树得到第t棵回归树,其对应的叶子节点面积为$R_{tj},j=1,2,...,J$。其中J是回归树t的叶节点数。c)对于叶面积$j=1,2,..J$,计算最佳拟合值$$c_{tj}=\underbrace{arg\;min}_{c}\sum\limits_{x_i\inR_{tj}}L(y_i,f_{t-1}(x_i)+c)$$d)更新强学习器$$f_{t}(x)=f_{t-1}(x)+\sum\limits_{j=1}^{J}c_{tj}I(x\inR_{tj})$$3)得到强学习器f的表达式(x)$$f(x)=f_T(x)=f_0(x)+\sum\limits_{t=1}^{T}\sum\limits_{j=1}^{J}c_{tj}I(x\inR_{tj})$$twoMetaGBDT分类算法对于二元GBDT,如果使用类似逻辑回归的对数似然损失函数,则损失函数为:$L(y,f(x))=log(1+exp(-yf(x)))$其中y∈{?1,+1}。那么此时的负梯度误差为$$r_{ti}=-\bigg[\frac{\partialL(y,f(x_i)))}{\partialf(x_i)}\bigg]_{f(x)=f_{t-1}\;\;(x)}=y_i/(1+exp(y_if(x_i)))$$    对于生成的决策树,我们的每个叶节点的最佳negative的梯度拟合值为$$c_{tj}=\underbrace{arg\;min}_{c}\sum\limits_{x_i\inR_{tj}}log(1+exp(-y_i(f_{t-1}(x_i)+c)))$$    自上公式很难优化,我们一般用近似值代替$$c_{tj}=\sum\limits_{x_i\inR_{tj}}r_{ti}\bigg/\sum\limits_{x_i\inR_{tj}}|r_{ti}|(1-|r_{ti}|)$$除了叶子节点的负梯度计算和最佳负梯度拟合线性搜索,二值GBDT分类和GBDT回归算法过程是相同。小例子+对GBDT的直观理解经过上面的原理分析,我对GBDT有了一个大概的了解。为了更形象地说明GBDT的内部执行过程,这里附上《统计学习方法》进一步分析的adaboost部分的案例数据。强烈建议大家对比学习,看看Adaboost和GBDT的区别和联系。数据集如下:GBDT用于训练。为了方便起见,我们使用MSE作为损失函数,并将树的深度设置为1,决策树的数量设置为5,其他参数使用默认值。将numpy导入为npimportpandas作为pdfromsklearnimporttreeimportmatplotlib.pyplotaspltfromsklearn.ensemble从sklearn.model_selection导入GradientBoostingRegressor导入train_test_splitX=np.arange(1,11)y=np.array([5.56,5.70,5.91,6.40,8.80,9.00,,9.05])display(X,y)gbdt=GradientBoostingRegressor(n_estimators=5,max_depth=1)gbdt.fit(X.reshape(-1,1),y)其中GradientBoostingRegressor的主要参数是如下GradientBoostingRegressor(alpha=0.9,criterion='friedman_mse',init=None,learning_rate=0.1,loss='ls',max_depth=1,max_features=None,max_leaf_nodes=None,min_impurity_decrease=0.0,min_impurity_split=None,min_samples_leaf=1,min_samples_split=2,min_weight_0,n_estimators=5,n_iter_no_change=None,presort='auto',random_state=None,subsample=1.0,tol=0.0001,validation_fraction=0.1,verbose=0,warm_start=False)其他参数是决策树参数,大家应该很熟悉,就不去了详细信息如下。GBDT回归算法原理,开始一步步硬核拆解:第一步:根据初始化公式$f_0(x)=\underbrace{arg\;min}_{c}\sum\limits_{i=1}^{m}L(y_i,c)$可以计算出$F_{0}(x)=7.307$(本例中恰好是均值yi的值)第二步:计算损失函数的负梯度值:$$r_{ti}=-\bigg[\frac{\partialL(y_i,f(x_i)))}{\partialf(x_i)}\bigg]_{f(x)=f_{t-1}\;\;(x)}$$由于是MSEloss,所以上式等于$\hat{y}_i=y_i-F_{m-1}(x_i)$,结果如下:#计算残差y-y.mean()[out]:array([-1.747,-1.607,-1.397,-0.907,-0.507,-0.257,1.593,1.393,1.693,1.743])第3步:将第一棵树拟合到以上残差根据给定的Data,可以考虑的分割点有1.5、2.5、3.5、4.5、5.5、6.5、7.5、8.5、9.5分别计算$y_i-F_{0}(x_i)$的值,并计算分割后的左右两边加上MSE最小的分割,最终结果为6.5找到最佳分割点后,我们就可以得到每个叶子节点的面积,计算$R_{jm}$和$\gamma_{jm}$。此时$R_{11}$为$x$小于6.5的数据,$R_{21}$为x大于6.5的数据。同时,

$$r_{11}=\frac{1}{6}\sum_{x_i\inR_{11}}y_{i}=-1.0703$$

$$r_{21}=\frac{1}{4}\sum_{x_i\inR_{21}}y_{i}=1.6055$$

print((y-y.mean())[:6].mean(),(y-y.mean())[6:10].mean())[out]:-1.071.605#Calculatemseprint(((y-y.mean())**2).mean(),((y[:6]-y[:6].mean())**2).mean(),((y[6:10]-y[6:10].mean())**2).mean())[out]1.9114210.3096890.0179686第一棵树的可视化tree.plot_tree(gbdt[0,0],filled=True)最后:更新$F_{1}(x_i)$值$F_1(x_i)=F_{0}(x_i)+\rho_m\sum^2_{j=1}\gamma_{j1}I(x_i\inR_{j1})$,其中$\rho_m$为learningrate,或者说shrinkage,用于防止预测结果过拟合,默认值为0.1。至此,第一轮迭代完成,后续迭代方法同上。在这个例子中,我们生成了5棵树。您可以使用tree.plot_tree来可视化其他树。课后作业大家可以想一想,第二棵树中的值是怎么计算的呢?其实很简单。迭代$m$次后,$m$次的$F_{m}(x)$就是最终的预测结果。

$$
F_{m}(x)=F_{m-1}(x)+\rho_{m}h(x;a_m)$$

参考https://www.cnblogs.com/pinar...https://blog.csdn.net/u014168...https://www.csuldw.com/2019/0...