本系列为深入篇,尽可能完善专题知识,并不会所有的都会出现在面试中,更多内容,详见:Reflection_Summary,欢迎交流。
另外,欢迎大家关注我的个人bolg,知乎,更多代码内容欢迎follow我的个人Github,如果有任何算法、代码疑问都欢迎通过邮箱发消息给我。
介绍一下Boosting的思想?
- 初始化训练一个弱学习器,初始化下的各条样本的权重一致
- 根据上一个弱学习器的结果,调整权重,使得错分的样本的权重变得更高
- 基于调整后的样本及样本权重训练下一个弱学习器
- 预测时直接串联综合各学习器的加权结果
最小二乘回归树的切分过程是怎么样的?
- 回归树在每个切分后的结点上都会有一个预测值,这个预测值就是结点上所有值的均值
- 分枝时遍历所有的属性进行二叉划分,挑选使平方误差最小的划分属性作为本节点的划分属性
- 属性上有多个值,则需要遍历所有可能的属性值,挑选使平方误差最小的划分属性值作为本属性的划分值
- 递归重复以上步骤,直到满足叶子结点上值的要求
有哪些直接利用了Boosting思想的树模型?
adaboost,gbdt等等
gbdt和boostingtree的boosting分别体现在哪里?
- boostingtree利用基模型学习器,拟合的是当前模型与标签值的残差
- gbdt利用基模型学习器,拟合的是当前模型与标签值的残差的负梯度
gbdt的中的tree是什么tree?有什么特征?
Cart tree,但是都是回归树
常用回归问题的损失函数?
- mse:
- 负梯度:y-h(x)
- 初始模型F0由目标变量的平均值给出
- 绝对损失:
- 负梯度:sign(y-h(x))
- 初始模型F0由目标变量的中值给出
- Huber损失:mse和绝对损失的结合
- 负梯度:y-h(x)和sign(y-h(x))分段函数
- 它是MSE和绝对损失的组合形式,对于远离中心的异常点,采用绝对损失,其他的点采用MSE,这个界限一般用分位数点度量
常用分类问题的损失函数?
- 对数似然损失函数
- 二元且标签y属于{-1,+1}:(,())=(1+(−()))
- 负梯度:y/(1+(−()))
- 多元:
- 二元且标签y属于{-1,+1}:(,())=(1+(−()))
- 指数损失函数:(,())=(−())
- 负梯度:y·(−())
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多元GBDT分类和二元GBDT分类以及GBDT回归算法过程相同
- 负梯度:y·(−())
什么是gbdt中的残差的负梯度?
,gbdt中的残差的负梯度的结果y-H(x)正好与boostingtree的拟合残差一致
如何用损失函数的负梯度实现gbdt?
- 利用
- 构建回归树的过程中,需要考虑找到特征A中最合适的切分点,使得切分后的数据集D1和D2的均方误差最小
- 针对每一个叶子节点里的样本,我们求出使损失函数最小,也就是拟合叶子节点最好的输出值,
- 首先,根据feature切分后的损失均方差大小,选取最优的特征切分
- 其次,根据选定的feature切分后的叶子结点数据集,选取最使损失函数最小,也就是拟合叶子节点最好的输出值
- 这样就完整的构造出一棵树:
- 本轮最终得到的强学习器的表达式如下:
拟合损失函数的负梯度为什么是可行的?
- 泰勒展开的一阶形式:
- m轮树模型可以写成:
- 对
- 对
- 我们拟合了残差的负梯度,
即便拟合损失函数负梯度是可行的,为什么不直接拟合残差? 拟合负梯度好在哪里?
- 前者不用残差的负梯度而是使用残差,是全局最优值,后者使用的是 局部最优方向(负梯度)*步长()
- 依赖残差进行优化,损失函数一般固定为反映残差的均方差损失函数,因此 当均方差损失函数失效(该损失函数对异常值敏感)的时候,换了其他一般的损失函数,便很难得到优化的结果。同时,因为损失函数的问题,Boosting Tree也很难处理回归之外问题。 而后者使用梯度下降的方法,对于任意可以求导的损失函数它都可以处理
Shrinkage收缩的作用?
每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易得到精确值,即它不完全信任每一棵残差树,认为每棵树只学到了真理的一部分累加的时候只累加了一小部分多学几棵树来弥补不足。 这个技巧类似于梯度下降里的学习率
- 原始:
- Shrinkage:
feature属性会被重复多次使用么?
会,同时因为特征会进行多次使用,特征用的越多,则该特征的重要性越大
gbdt如何进行正则化的?
- 子采样
- 每一棵树基于原始原本的一个子集进行训练
- rf是有放回采样,gbdt是无放回采样
- 特征子采样可以来控制模型整体的方差
- 利用Shrinkage收缩,控制每一棵子树的贡献度
- 每棵Cart树的枝剪
为什么集成算法大多使用树类模型作为基学习器?或者说,为什么集成学习可以在树类模型上取得成功?
- 对数据的要求比较低,不需要强假设,不需要数据预处理,连续离散都可以,缺失值也能接受
- bagging,关注于提升分类器的泛化能力
- boosting,关注于提升分类器的精度
gbdt的优缺点?
优点:
- 数据要求比较低,不需要前提假设,能处理缺失值,连续值,离散值
- 使用一些健壮的损失函数,对异常值的鲁棒性非常强
- 调参相对较简单
缺点:
- 并行化能力差
gbdt和randomforest区别?
- 相同:
- 都是多棵树的组合
- 不同:
- RF每次迭代的样本是从全部训练集中有放回抽样形成的,而GBDT每次使用全部样本
- gbdt对异常值比rf更加敏感
- gbdt是串行,rf是并行
- gbdt是cart回归树,rf是cart分类回归树都可以
- gbdt是提高降低偏差提高性能,rf是通过降低方差提高性能
- gbdt对输出值是进行加权求和,rf对输出值是进行投票或者平均
GBDT和LR的差异?
- 从决策边界来说,线性回归的决策边界是一条直线,逻辑回归的决策边界是一条曲线,而GBDT的决策边界可能是很多条线
- 当在高维稀疏特征的场景下,LR的效果一般会比GBDT好。因为LR有参数惩罚,GBDT容易造成过拟合
XGboost缺点
- 每轮迭代时,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间
- 预排序方法需要保存特征值,及特征排序后的索引结果,占用空间
- level-wise,在训练的时候哪怕新增的分裂点对loss增益没有提升也会先达到预定的层数
LightGBM对Xgboost的优化
- 将连续的浮点特征离散成k个离散值,具体过程是首先确定对于每一个特征需要多少的桶bin,然后均分,将属于该桶的样本数据更新为bin的值,最后用直方图表示。在进行特征选择时,只需要根据直方图的离散值,遍历寻找最优的分割点
- 优点:时间开销由O(features)降低到O(bins)
- 缺点:很多数据精度被丢失,相当于用了正则
- 利用leaf-wise代替level-wise
- 每次从当前所有叶子中找到分裂增益最大(一般也是数据量最大)的一个叶子,然后分裂,如此循环
- 直方图做差加速
LightGBM亮点
- 单边梯度采样 Gradient-based One-Side Sampling (GOSS):排除大部分小梯度的样本,仅用剩下的样本计算损失增益
- 互斥稀疏特征绑定Exclusive Feature Bundling (EFB):从减少特征角度,把尽可能互斥的特征进行合并,比如特征A[0,10],特征B[0,20],可以把B+10后与A合并,得到新特征A+B[0,30]
xgboost对比gbdt/boosting Tree有了哪些方向上的优化?
- 显示的把树模型复杂度作为正则项加到优化目标中
- 优化目标计算中用到二阶泰勒展开代替一阶,更加准确
- 实现了分裂点寻找近似算法
- 暴力枚举
- 近似算法(分桶)
- 更加高效和快速
- 数据事先排序并且以block形式存储,有利于并行计算
- 基于分布式通信框架rabit,可以运行在MPI和yarn上
- 实现做了面向体系结构的优化,针对cache和内存做了性能优化
xgboost和gbdt的区别?
- 模型优化上:
- 基模型的优化:
- gbdt用的是cart回归树作为基模型,xgboost还可以用线性模型,加上天生的正则项,就是带L1和L2逻辑回归(分类)和线性回归(回归)
- 损失函数上的优化:
- gbdt对loss是泰勒一阶展开,xgboost是泰勒二阶展开
- gbdt没有在loss中带入结点个数和预测值的正则项
- 特征选择上的优化:
- 实现了一种分裂节点寻找的近似算法,用于加速和减小内存消耗,而不是gbdt的暴力搜索
- 节点分裂算法解决了缺失值方向的问题,gbdt则是沿用了cart的方法进行加权
- 正则化的优化:
- 特征采样
- 样本采样
- 基模型的优化:
- 工程优化上:
- xgboost在对特征进行了分block预排序,使得在做特征分裂的时候,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行
- cache-aware, out-of-core computation
- 支持分布式计算可以运行在MPI,YARN上,得益于底层支持容错的分布式通信框架rabit
xgboost优化目标/损失函数改变成什么样?
- 原始:
-
- 改变:
- J为叶子结点的个数,
为第j个叶子结点中的最优值
-
- J为叶子结点的个数,
xgboost如何使用MAE或MAPE作为目标函数?
MAE:MAPE:
- 利用可导的函数逼近MAE或MAPE
- mse
- Huber loss
- Pseudo-Huber loss
xgboost如何寻找分裂节点的候选集?
- 暴力枚举
- 法尝试所有特征和所有分裂位置,从而求得最优分裂点。当样本太大且特征为连续值时,这种暴力做法的计算量太大
- 近似算法(approx)
- 近似算法寻找最优分裂点时不会枚举所有的特征值,而是对特征值进行聚合统计,然后形成若干个桶。然后仅仅将桶边界上的特征的值作为分裂点的候选,从而获取计算性能的提升
- 离散值直接分桶
- 连续值分位数分桶
- 近似算法寻找最优分裂点时不会枚举所有的特征值,而是对特征值进行聚合统计,然后形成若干个桶。然后仅仅将桶边界上的特征的值作为分裂点的候选,从而获取计算性能的提升
xgboost如何处理缺失值?
- 训练时:缺失值数据会被分到左子树和右子树分别计算损失,选择较优的那一个
- 预测时:如果训练中没有数据缺失,预测时出现了数据缺失,那么默认被分类到右子树
xgboost在计算速度上有了哪些点上提升?
- 特征预排序
- 按特征进行存储,每一个block代表一个特征的值,样本在该block中按照它在该特征的值排好序。这些block只需要在程序开始的时候计算一次,后续排序只需要线性扫描这些block即可
- block可以仅存放样本的索引,而不是样本本身,这样节省了大量的存储空间
xgboost特征重要性是如何得到的?
- ’weight‘:代表着某个特征被选作分裂结点的次数;
- ’gain‘:使用该特征作为分类结点的信息增益;
- ’cover‘:某特征作为划分结点,覆盖样本总数的平均值;
XGBoost中如何对树进行剪枝?
- 在目标函数中增加了正则项:叶子结点树+叶子结点权重的L2模的平方
- 在结点分裂时,定义了一个阈值,如果分裂后目标函数的增益小于该阈值,则不分裂
- 当引入一次分裂后,重新计算新生成的左、右两个叶子结点的样本权重和。如果任一个叶子结点的样本权重低于某一个阈值(最小样本权重和),也会放弃此次分裂
- XGBoost 先从顶到底建立树直到最大深度,再从底到顶反向检查是否有不满足分裂条件的结点,进行剪枝
XGBoost模型如果过拟合了怎么解决?
- 直接修改模型:
- 降低树的深度
- 增大叶子结点的权重
- 增大惩罚系数
- subsample的力度变大,降低异常点的影响
- 减小learning rate,提高estimator
xgboost如何调参数?
- 先确定learningrate和estimator
- 再确定每棵树的基本信息,max_depth和 min_child_weight
- 再确定全局信息:比如最小分裂增益,子采样参数,正则参数
- 重新降低learningrate,得到最优解