gbdt推导和代码
GBDT算法推导过程
m次迭代,n个类别,那么就意味着学习了m*n棵回归树
train过程:假设有8个训练样本,3个类别
步骤一、假设所有样本的F矩阵,F矩阵是8*3的,F矩阵刚开始全为0,而实际每个样本都有一个属于的类别y,y能组成一个实际的矩阵也是8*3的
步骤二、决策树是不断学习残差的过程,这里的残差经过计算是y-p,其中p是由F矩阵求出来的,即
这里要知道决策树的分裂依据:遍历所有的特征纬度,这里是3个特征,对于每一个特征,选择一个合适的分裂点,
如果属性是数字
也就是遍历所有那个属性的值,eg[10,20,30,40,50,60,70]然后分类节点假设是3个的话就需要从中随机采样3个数据作为属性,eg[20,40,60],那么在这个属性进行遍历的时候就可以以该点的值作为分界限,分割左右子树
如果属性是标量
就直接按照节点属性是否等于标量为分界线,分隔左右子树
如何选择最佳属性和最佳分隔点:
我们已经将树分隔成了左右子树了,那么怎么从那么多的分隔中选择最佳的分隔点呢
这里,leftTargets,rightTargets都是左右子树样本点的残差,也就是前面的y-p的值,所以这里分隔的依据是:选择左右子树损失函数在当前模型的梯度的均方根误差和最小
节点分类的依据是:均方根误差(RMSE),均方根误差为了说明样本的离散程度
eg,第一组样本:3,4,5
第二组样本:2,4,6
两组的平均值都是4,但是第一组相对更加接近平均值,离散程度小,均方根误差就表示这个
这样一直分割下去,只要不超过最大深度,一直到达叶子节点
这里用均方根误差,就是让属于同一特性的被分到一起,减少离散
叶子节点的值:
其中:
建立好一棵树后,需要更新F矩阵,
接着再更加F矩阵和y矩阵重新计算残差,重新生成新的树,这样迭代M次,F矩阵是在不断地逼近y矩阵的(注意,这里的3个类的决策树是同时进行的,也就是一次迭代,生成的是3棵树,如下代码所示:
测试
将测试样本输入到m*n棵树中,每个类别是m棵树,不断累加这m棵树的的结果就是最终的f[instance_id]的值,然后选择值最大的f作为最终的label
公式推导部分:
简言之:最小化目标函数,泰勒展开,f’(x)=0求得叶子节点的值,x=-f'(0)/f"(0),其实也是牛顿法在初值为0的
时候下一个更新值(或者在x=0处泰勒展开到二阶,然后求导,也能得到x=-f'(0)/f"(0)),这里实际是求f'(x)=0的x对应的值,对于多类的叶子节点中的k-1/k,自己没有推出,后面的公式是对应的
两个版本之间的联系
前面我们提到的一些联系,这儿再总结一下:
- 基于残差的版本四把残差作为全局方向,偏向于回归的应用。而基于梯度的版本是把代价函数的梯度方向作为更新的方向,适用范围更广。
- 如果使用Logistic函数作为代价函数,那么其梯度形式和残差的形式类似,这个就说明两个版本之间是紧密联系的,虽然实现的思路不同,但是总体的目的是一样的。或者说残差版本是梯度版本的一个特例,当代价函数换成其余的函数,梯度的版本仍是适用的。
关于gbdt时间复杂度的计算:
针对每个特征,把属于该节点的训练样本根据该特征值升序排列,通过线性扫描的方式来决定该特征的最佳分裂点,并记录该特征的最大收益(采用最佳分裂点时的收益)
时间复杂度nlogn * d * m(n是样本个数,d是特征个数,m是树的深度)
论文名字:
Greedy function approximation : A Gradient Boosting Machine
原文:http://www.cnblogs.com/wuxiangli/p/5973737.html