归一化可以提高收敛速度,提高收敛的精度
归一化:最大值、均值
标准化:Z-score
离散化:分段,等频等距
将用户和物品分别用k维的低维向量表示。
mn —> mk + n*k
(其实就是推荐中的矩阵分解)
删除:
填补:离散的用众数、连续的取平均数
(1)错误率(Error rate)和精度(Accuracy)
(2)查准率(准确率-Precision)、查全率(召回率-Recall)
(3)P-R曲线、平衡点和F1衡量
(4)ROC、AUC
前三类指标的详细介绍
ROC、AUC详细介绍
accuracy=correct/total
缺点:当样本比例非常不均衡时,占比大的类别会成为影响准确率的最主要因素。当负样本只有1%,即使全部判为负也可以实现99%的准确率。
离群点是很可能的原因。事实上流量预估问题中,噪声是很容易出现的(刚上映的热播剧,突发事件)
roc曲线经常作为评估二分类最重要的指标之一
roc曲线的横坐标是假阳性率:FP/N
纵坐标是真阳性率: TP/P
AUC就是ROC曲线的面积,越大越好
当正负样本分布发生变化时,ROC曲线形状基本不变,PR会发生剧烈变化。
ROC曲线不局限于特定数据集,广泛应用于排序、推荐、广告领域。
如果研究者更希望看到特定数据集的表现,可选用PR
这个问题的本质原因,在于横轴FPR只关注负样本,与正样本无关;纵轴TPR只关注正样本,与负样本无关。所以横纵轴都不受正负样本比例影响,积分当然也不受其影响。
在文本、图像、视频等领域,对象的特征维度往往很高,适合余弦,欧式距离的数值受维度的影响。
比如用户观看行为A(1,0),B(0,1)就要用余弦,而分析用户活跃度时以登陆次数和平均时长作为特征时,A(1,10),B(10,100)就要用欧氏距离。
主要手段是用户分桶,分为实验组和对照组,分桶要注意样本的独立性和采样方式的无偏性,userid需要是随机数。
问题:
细节可以参考
直接对训练集中多数类样本进行“欠采样”
对训练集里的少数类进行“过采样”(oversampling),即增加一些少数类样本使得正、反例数目接近,然后再进行学习
采样算法从数据层面解决不平衡数据的学习问题;在算法层面上解决不平衡数据学习的方法主要是基于代价敏感学习算法
(1)在正负样本都非常少的情况下,应该采用数据合成的方式,例如:SMOTE算法
(2)在正负样本都足够多且比例不是特别悬殊的情况下,应该考虑采样的方法或者是加权的方法。
判别式模型和生成式模型都是使后验概率最大化,判别式是直接对后验概率建模,而生成式模型通过贝叶斯定理这一“桥梁”使问题转化为求联合概率
这个式子的更新速度只和xi,yi相关。和sigmoid函数本身的梯度无关,这样更新的速度是可以自始至终都比较的稳定。至于为什么不用平方损失函数,使用平方损失函数的话梯度更新的速度和sigmod函数本身的梯度是很相关的。sigmod函数在它在定义域内的梯度都不大于0.25。这样训练会非常的慢
联系:
1、LR和SVM都可以处理分类问题,且一般都用于处理线性二分类问题(在改进的情况下可以处理多分类问题)
2、两个方法都可以增加不同的正则化项,如l1、l2等等。所以在很多实验中,两种算法的结果是很接近的。
区别:
1、LR是参数模型,SVM是非参数模型。
2、从目标函数来看,区别在于逻辑回归采用的是logistical loss,SVM采用的是hinge loss,这两个损失函数的目的都是增加对分类影响较大的数据点的权重,减少与分类关系较小的数据点的权重。
3、支持向量机只考虑局部的边界线附近的点,而逻辑回归考虑全局(远离的点对边界线的确定也起作用)
4、SVM的损失函数就自带正则。
5、logic 能做的 svm能做,但可能在准确率上有问题,svm能做的logic有的做不了。
将M个样本的标签构成一个M维的标签向量,M个N维特征向量构成一个M*N的样本矩阵,如图3所示。其中特征矩阵每一行为一个特征向量(M行),列为特征维度(N列)
SVM1
最优规划大体分两种,无约束规划和约束规划 ,拉格朗日量可以将“约束”转换成“无约束”
关系式 y ( i ) ( w T x ( i ) + b ) > 0 y(i)(w^Tx(i) + b) > 0 y(i)(wTx(i)+b)>0 永远成立。
在 m 点中,离超平面 h 最近点的距离,也就是间隔
在 SVM 问题中,我们不但希望要最大化 margin,还希望每个点都有分类正确,因为我们要解决下面优化问题
目标函数是个二次凸函数,非常适合做优化;但是限制条件里面有 min 出现,给优化问题造成了难度。因此我们将这一个带 min 的限制条件转换成 m 个“更松”的限制条件,如下
最终要解决的问题是:
hard-margin SVM 的对偶问题
根据附录1的详细推导,我们得到标准化 hard-margin SVM 的对偶问题
原始问题是通过求 b 和 w 来最小化目标函数,而对偶问题是通过求 α 来最小化目标函数,其矩阵形式为
此问题也是一个二次规划问题,虽然可以用 KKT 手动解出,但通常还是利用软件里面自带的函数去解
附录一:
要从 x 空间转换成 z 空间,就必须要从计算 xTx’ 到计算 zTz’
定义K(x, x’) = zTz’ 为核函数
巧妙定义函数可以非常容易计算出来
SVM2
硬线性分隔 SVM 对偶问题和它的最优解
当数据的特征提取的较好,所包含的信息量足够大,很多问题是线性可分的那么可以采用线性核。若特征数较少,样本数适中,对于时间不敏感,遇到的问题是线性不可分的时候可以使用高斯核来达到更好的效果
过拟合是方差大,欠拟合是偏差大
产生过拟合原因:
参数太多,模型复杂度高
样本中噪音数据较大,模型学习到了噪音中的特征
对于决策树模型。对决策树的生长没有合理的限制和修建
对于神经网络模型。权值学习迭代次数足够多(overtraining),拟合了训练数据中的噪声和训练样例中没有代表性的特征。
解决方案:
降低模型复杂度
增大训练集,训练集增加之后就能学习到更多具有代表性的特征
增加正则项,减少参数,进一步降低模型复杂度
对于神经网络,采用dropout
对于决策树,采用earlystopping,模型对训练数据集迭代收敛之前停止,防止过拟合
采用ensemble。集成学习可以有效的减轻过拟合。bagging通过平均多个模型的结果,来降低模型的方差。boosting不仅可以减小偏差,还可以减小方差。
正则化就是结构风险最小化策略的实现,是在经验风险最小化的情况下加入一个正则化项或者罚项。
范数是一种用来度量某个向量空间(或矩阵)中的每个向量的长度或大小的手段。
正则化是结构风险最小化策略的实现,L1和L2正则化属于正则化手段中的两种实现方式,L1正则化是在损失函数中加入 参数向量中各个元素的绝对值之和作为损失函数的惩罚项的,L2正则化是在损失函数中加入 参数向量中各个元素的平方,求和,然后再求平方根作为损失函数的惩罚项的。这就是二者的原理与区别。
L1正则化代表的约束条件的多维空间是超立方体和坐标轴存在很多“角”交点,目标函数大部分时候会在“角”的地方和约束条件相交,所以L1正则化容易产生稀疏的参数向量,而L2正则化是一个超球体,因为没有“角”交点,所以第一次相交的地方出现在具有稀疏性的位置的概率就变得非常小了,所以L2正则化容易产生平滑的参数向量。
L1就是按绝对值函数的“坡”下降的,而L2是按二次函数的“坡”下降。所以实际上在0附近根据其梯度,L1的下降速度比L2的下降速度要快
防止过拟合的具体表现:在不显著增大偏差的的同时,显著减小模型的方差
L1正则化除了防止过拟合还可以作为特征筛选的方法,使得对模型不是太重要的特征的权重系数趋于0,那么我们就可以根据具体情况来对特征进行删除和重选择,从而起到提高泛化性能以及节约内存空间,提升运行效率的作用。
由于lasso回归的损失函数是不可导的,所以梯度下降算法将不再有效,下面利用坐标轴下降法进行求解。
坐标轴下降法和梯度下降法具有同样的思想,都是沿着某个方向不断迭代,但是梯度下降法是沿着当前点的负梯度方向进行参数更新,而坐标轴下降法是沿着坐标轴的方向
坐标轴下降法进行参数更新时,每次总是固定另外m-1个值,求另外一个的局部最优值,这样也避免了Lasso回归的损失函数不可导的问题。
坐标轴下降法每轮迭代都需要O(mn)的计算。(和梯度下降算法相同)
Ridge=线性回归+L2正则,有闭合解;Lasso=线性回归+L1正则,无闭合解,可用坐标梯度下降求解
不会,因为训练时dropout机制会把dropout_rate = p的输出乘以1/(1-p)
决策树算法,无论是哪种,其目的都是为了让模型的不确定性降低的越快越好,基于其评价指标的不同,主要是ID3算法,C4.5算法和CART算法,其中ID3算法的评价指标是信息增益,C4.5算法的评价指标是信息增益率,CART算法的评价指标是基尼系数。
ID3:
C4.5:
CART:
会倾向于去选择特征取值比较多的特征作为最优特征。举个比较极端的例子,如果将身份证号作为一个属性,这个属性可以完美划分但是毫无意义
信息增益率的公式如下:
原因:
这时就要想起我们之前的目的:在降维后的每一维度上,方差最大。而方差最大,则容易想到的就是协方差矩阵,去中心化后,协方差矩阵的对角线上的值正好就是各个数据维度的方差
若使用PCA将数据点投影至一维空间上时,PCA会选择2轴,这使得原本很容易区分的两簇点被揉杂在一起变得无法区分;而这时若选择1轴将会得 到很好的区分结果
LDA原理
降维之后的维数最多为类别数-1。所以当数据维度很高,但是类别数少的时候,算法并不适用
采用了“属性条件独立性假设”:对已知类别,假设所有属性相互独立。换言之,假设每个属性独立地对分类结果发生影响。
优点:对小规模的数据表现很好,适合多分类任务,适合增量式训练。
缺点:对输入数据的表达形式很敏感(离散、连续,值极大极小之类的)。
用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数
HMM
可见状态链/隐含状态链
预测过程比较简单,就是利用维特比算法。我们先以分词为例说明维特比要做的事情。给定一个观测的序列如“北京信息科技大学”,利用维特比算法,系统可以求出一个最佳的状态序列比如是“BEBEBEBE”。
EM(Expectation-Maximum)算法也称期望最大化算法,常被用来学习高斯混合模型(Gaussian mixture model,简称GMM)的参数;隐式马尔科夫算法(HMM)、LDA主题模型的变分推断等等
我们已知的条件有两个:样本服从的分布模型、随机抽取的样本。我们需要求解模型的参数。根据已知条件,通过极大似然估计,求出未知参数。总的来说:极大似然估计就是用来估计模型参数的统计学方法
多数情况下,我们是根据已知条件来推算结果,而极大似然估计是已知结果,寻求使该结果出现的可能性最大的条件,以此作为估计值
优点:1、在数据集上表现良好,相对于其他算法有较大的优势(训练速度、预测准确度);2、能够处理很高维的数据,并且不用特征选择,而且在训练完后,给出特征的重要性;3、容易做成并行化方法。
缺点:在噪声较大的分类或者回归问题上会过拟合。
流程和实际例子
AdaBoost的做法是,提高那些被前一轮弱分类器错误分类样本的权值,而降低那些被正确分类样本的权值。这样一来,那些没有得到正确分类的数据,由于其权值的加大而受到后一轮的弱分类器的更大关注。于是,分类问题被一系列的弱分类器“分而治之”。
弱分类器的组合,AdaBoost采取加权多数表决的方法。具体地,加大分类误差率小的弱分类器的权值,使其在表决中起较大的作用,减小分类误差率大的弱分类器的权值,使其在表决中起较小的作用
提升树模型每一次的提升都是靠上次的预测结果与训练数据中label值的差值作为新的训练数据进行重新训练,由于原始的回归树指定了平方损失函数所以可以直接计算残差,而梯度提升决策树(Gradient Boosting Decision Tree, GDBT)针对的是一般损失函数,所以采用负梯度来近似求解残差,将残差计算替换成了损失函数的梯度方向,将上一次的预测结果带入梯度中求出本轮的训练数据。这两种模型就是在生成新的训练数据时采用了不同的方法
提升树利用加法模型与前向分歩算法实现学习的优化过程。当损失函数是平方误差损失函数和指数损失函数时,每一步优化是很简单的。但对一般损失函数而言,往往每一步优化并不那么容易。针对这一问题,Freidman提出了梯度提升(gradient boosting)算法。它的思想借鉴于梯度下降法,其基本原理是根据当前模型损失函数的负梯度信息作为提升树算法中残差的近似值,拟合一个梯度提升模型
两者都是在每一轮迭代中,利用损失函数相对于模型的负梯度方向的信息来对当前模型进行更新,只不过在梯度下降中,模型是以参数化形式表示,从而模型的更新等价于参数的更新。而在梯度提升中,模型并不需要进行参数化表示,而是直接定义在函数空间中,从而大大扩展了可以使用的模型种类。
推导
Gradient Boosting是Boosting中的一大类算法,其中包括:GBDT(Gradient Boosting Decision Tree)、XGBoost(eXtreme Gradient Boosting)、LightGBM (Light Gradient Boosting Machine)和CatBoost(Categorical Boosting)等
gbdt实际例子
回归树
这里面的核心是因为GBDT 每轮的训练是在上一轮的训练的残差基础之上进行训练的。
这里的残差就是当前模型的负梯度值 。这个要求每轮迭代的时候,弱分类器的输出的结果相减是有意义的。残差相减是有意义的。而类别结果相减是无意义的,因此需要数值结果进行相减,所以使用CART 回归树。
当CART是分类树时,采用GINI值作为节点分裂的依据;当CART是回归树时,采用样本的最小方差作为节点分裂的依据
CART
gbdt实际例子
GBDT的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量
比如A的真实年龄是18岁,但第一棵树的预测年龄是12岁,差了6岁,即残差为6岁。那么在第二棵树里我们把A的年龄设为6岁去学习,如果第二棵树真的能把A分到6岁的叶子节点,那累加两棵树的结论就是A的真实年龄;如果第二棵树的结论是5岁,则A仍然存在1岁的残差,第三棵树里A的年龄就变成1岁,继续学。
gbdt通过多轮迭代,每轮迭代产生一个弱分类器,每个分类器在上一轮分类器的残差基础上进行训练。
对弱分类器的要求一般是足够简单,并且是低方差和高偏差的。因为训练的过程是通过降低偏差来不断提高最终分类器的精度。
具体到损失函数本身的选择也就是L的选择,有平方损失函数,0-1损失函数,对数损失函数等等。如果我们选择平方损失函数,那么这个差值其实就是我们平常所说的残差。
GBDT每轮迭代的时候,都去拟合损失函数在当前模型下的负梯度。
这样每轮训练的时候都能够让损失函数尽可能快的减小,尽快的收敛达到局部最优解或者全局最优解。
CART TREE 生成的过程其实就是一个选择特征的过程。假设我们目前总共有 M 个特征。第一步我们需要从中选择出一个特征 j,做为二叉树的第一个节点。然后对特征 j 的值选择一个切分点 m. 一个 样本的特征j的值如果小于m,则分为一类,如果大于m,则分为另外一类。如此便构建了CART 树的一个节点。其他节点的生成过程和这个是一样的
具体到分类这个任务上面来,我们假设样本 X 总共有 K类。来了一个样本 x,我们需要使用GBDT来判断 x 属于样本的哪一类。
第一步 我们在训练的时候,是针对样本 X 每个可能的类都训练一个分类回归树。举例说明,目前样本有三类,也就是 K = 3。样本 x 属于 第二类。那么针对该样本 x 的分类结果,其实我们可以用一个 三维向量 [0,1,0] 来表示。0表示样本不属于该类,1表示样本属于该类。由于样本已经属于第二类了,所以第二类对应的向量维度为1,其他位置为0。
针对样本有 三类的情况,我们实质上是在每轮的训练的时候是同时训练三颗树。第一颗树针对样本x的第一类,输入为(x,0)。第二颗树输入针对 样本x 的第二类,输入为(x,1)。第三颗树针对样本x 的第三类,输入为(x,0)
在这里每颗树的训练过程其实就是就是我们之前已经提到过的CATR TREE 的生成过程。在此处我们参照之前的生成树的程序 即可以就解出三颗树,以及三颗树对x 类别的预测值f1(x),f2(x),f3(x)。那么在此类训练中,我们仿照多分类的逻辑回归 ,使用softmax 来产生概率,则属于类别 1 的概率
并且我们我们可以针对类别1 求出 残差y11(x)=0−p1(x);类别2 求出残差y22(x)=1−p2(x);类别3 求出残差y33(x)=0−p3(x).
然后开始第二轮训练 针对第一类 输入为(x,y11(x)), 针对第二类输入为(x,y22(x)), 针对 第三类输入为 (x,y33(x)).继续训练出三颗树。一直迭代M轮。每轮构建 3颗树。
当训练完毕以后,新来一个样本 x1 ,我们需要预测该样本的类别的时候,便可以有这三个式子产生三个值,f1(x),f2(x),f3(x)。样本属于 某个类别c的概率为
GBDT基于树模型,继承了树模型的优点 :对异常点鲁棒、不相关的特征干扰性低(LR需要加正则)、可以很好地处理缺失值、受噪音的干扰小
1、首先使用默认的参数,进行数据拟合;
2、从步长(learning rate)和迭代次数(n_estimators)入手;一般来说,开始选择一个较小的步长来网格搜索最好的迭代次数。这里,可以将步长初始值设置为0.1。对于迭代次数进行网格搜索;
3、接下来对决策树的参数进行寻优
4、首先我们对决策树最大深度max_depth和内部节点再划分所需最小样本数min_samples_split进行网格搜索。【min_samples_split暂时不能一起定下来,因为这个还和决策树其他的参数存在关联】
5、接着再对内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf一起调参;做到这里,min_samples_split要做两次网格寻优,一次是树的最大深度max_depth,一次是叶子节点最少样本数min_samples_leaf。
【具体观察min_samples_split的值是否落在边界上,如果是可以进一步寻优】
6、继续对最大特征数max_features进行网格搜索。做完这一步可以看看寻找出的最优参数组合给出的分类器的效果。
7、可以进一步考虑对子采样的比例进行网格搜索,得到subsample的寻优参数
8、回归到第2步调整设定的步长(learning rate)和迭代次数(n_estimators),注意两者的乘积保持不变,这里可以分析得到:通过减小步长可以提高泛化能力,但是步长设定过小,也会导致拟合效果反而变差,也就是说,步长不能设置的过小。
如何调gbdt
A:优点
可以灵活处理各种类型的数据,包括连续值和离散值。
在相对少的调参时间情况下,预测的准备率也可以比较高。这个是相对SVM来说的。
使用一些健壮的损失函数,对异常值的鲁棒性非常强。比如 Huber损失函数和Quantile损失函数。
缺点:由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的SGBT来达到部分并行。
相同点:
都是由多棵树组成,最终的结果都是由多棵树一起决定。
不同点:
集成学习:RF属于bagging思想,而GBDT是boosting思想
偏差-方差权衡:RF不断的降低模型的方差,而GBDT不断的降低模型的偏差
训练样本:RF每次迭代的样本是从全部训练集中有放回抽样形成的,而GBDT每次使用全部样本
并行性:RF的树可以并行生成,而GBDT只能顺序生成(需要等上一棵树完全生成)
最终结果:RF最终是多棵树进行多数表决(回归问题是取平均),而GBDT是加权融合
数据敏感性:RF对异常值不敏感,而GBDT对异常值比较敏感
泛化能力:RF不易过拟合,而GBDT容易过拟合
先说说LR和GBDT的区别:
举例:
假设一个二分类问题,label为0和1,特征有100维,如果有1w个样本,但其中只要10个正样本1,而这些样本的特征 f1的值为全为1,而其余9990条样本的f1特征都为0(在高维稀疏的情况下这种情况很常见)。
我们都知道在这种情况下,树模型很容易优化出一个使用f1特征作为重要分裂节点的树,因为这个结点直接能够将训练数据划分的很好,但是当测试的时候,却会发现效果很差,因为这个特征f1只是刚好偶然间跟y拟合到了这个规律,这也是我们常说的过拟合。
那么这种情况下,如果采用LR的话,应该也会出现类似过拟合的情况呀:y = W1f1 + Wifi+….,其中 W1特别大以拟合这10个样本。为什么此时树模型就过拟合的更严重呢?
仔细想想发现,因为现在的模型普遍都会带着正则项,而 LR 等线性模型的正则项是对权重的惩罚,也就是 W1一旦过大,惩罚就会很大,进一步压缩 W1的值,使他不至于过大。但是,树模型则不一样,树模型的惩罚项通常为叶子节点数和深度等,而我们都知道,对于上面这种 case,树只需要一个节点就可以完美分割9990和10个样本,一个结点,最终产生的惩罚项极其之小。
这也就是为什么在高维稀疏特征的时候,线性模型会比非线性模型好的原因了:带正则化的线性模型比较不容易对稀疏特征过拟合
每一次的计算是为了减少上一次的残差(residual),而为了消除残差,我们可以在残差减少的梯度(Gradient)方向上建立一个新的模型。所以说,在Gradient Boost中,每个新的模型的建立是为了使得之前模型的残差往梯度方向减少,与传统Boost对正确、错误的样本进行加权有着很大的区别
AdaBoost和GBDT都是重复选择一个表现一般的模型并且每次基于先前模型的表现进行调整。不同的是,AdaBoost是通过调整错分数据点的权重来改进模型,GBDT是通过计算负梯度来改进模型。因此,相比AdaBoost, GBDT可以使用更多种类的目标函数,而当目标函数是均方误差时,计算损失函数的负梯度值在当前模型的值即为残差。
最终计算:
原理细节
首先需要说一说GBDT,它是一种基于boosting增强策略的加法模型,训练的时候采用前向分布算法进行贪婪的学习,每次迭代都学习一棵CART树来拟合之前 t-1 棵树的预测结果与训练样本真实值的残差。
XGBoost对GBDT进行了一系列优化,比如损失函数进行了二阶泰勒展开、目标函数加入正则项、支持并行和默认缺失值处理等,在可扩展性和训练速度上有了巨大的提升,但其核心思想没有大的变化
基分类器:XGBoost的基分类器不仅支持CART决策树,还支持线性分类器,此时XGBoost相当于带L1和L2正则化项的Logistic回归(分类问题)或者线性回归(回归问题)。
导数信息:XGBoost对损失函数做了二阶泰勒展开,GBDT只用了一阶导数信息,并且XGBoost还支持自定义损失函数,只要损失函数一阶、二阶可导。
正则项:XGBoost的目标函数加了正则项, 相当于预剪枝,使得学习出来的模型更加不容易过拟合。
列抽样:XGBoost支持列采样,与随机森林类似,用于防止过拟合。
缺失值处理:对树中的每个非叶子结点,XGBoost可以自动学习出它的默认分裂方向。如果某个样本该特征值缺失,会将其划入默认分支。
并行化:注意不是tree维度的并行,而是特征维度的并行。XGBoost预先将每个特征按特征值排好序,存储为块结构,分裂结点时可以采用多线程并行查找每个特征的最佳分割点,极大提升训练速度。
精准性:相对于GBDT的一阶泰勒展开,XGBoost采用二阶泰勒展开,可以更为精准的逼近真实的损失函数
可扩展性:损失函数支持自定义,只需要新的损失函数二阶可导。
XGBoost的并行,并不是说每棵树可以并行训练,XGB本质上仍然采用boosting思想,每棵树训练前需要等前面的树训练完成才能开始训练。
XGBoost的并行,指的是特征维度的并行:在训练之前,每个特征按特征值对样本进行预排序,并存储为Block结构,在后面查找特征分割点时可以重复使用,而且特征已经被存储为一个个block结构,那么在寻找每个特征的最佳分割点时,可以利用多线程对每个block并行计算
分块并行:训练前每个特征按特征值进行排序并存储为Block结构,后面查找特征分割点时重复使用,并且支持并行查找每个特征的分割点
候选分位点:每个特征采用常数个分位点作为候选分割点
CPU cache 命中优化: 使用缓存预取的方法,对每个线程分配一个连续的buffer,读取每个block中样本的梯度信息并存入连续的Buffer中。
Block 处理优化:Block预先放入内存;Block按列进行解压缩;将Block划分到不同硬盘来提高吞吐
XGBoost在设计时,为了防止过拟合做了很多优化,具体如下:
目标函数添加正则项:叶子节点个数+叶子节点权重的L2正则化
列抽样:训练的时候只用一部分特征(不考虑剩余的block块即可)
子采样:每轮计算可以不使用全部样本,使算法更加保守
shrinkage: 可以叫学习率或步长,为了给后面的训练留出更多的学习空间
XGBoost模型的一个优点就是允许特征存在缺失值。对缺失值的处理方式如下:
在特征k上寻找最佳 split point 时,不会对该列特征 missing 的样本进行遍历,而只对该列特征值为 non-missing 的样本上对应的特征值进行遍历,通过这个技巧来减少了为稀疏离散特征寻找 split point 的时间开销。
在逻辑实现上,为了保证完备性,会将该特征值missing的样本分别分配到左叶子结点和右叶子结点,两种情形都计算一遍后,选择分裂后增益最大的那个方向(左分支或是右分支),作为预测时特征值缺失样本的默认分支方向。
如果在训练中没有缺失值而在预测中出现缺失,那么会自动将缺失值的划分方向放到右子结点。
当新引入的一次分裂所带来的增益Gain<0时,放弃当前的分裂。这是训练损失和模型结构复杂度的博弈过程。
当树达到最大深度时,停止建树,因为树的深度太深容易出现过拟合,这里需要设置一个超参数max_depth。
当引入一次分裂后,重新计算新生成的左、右两个叶子结点的样本权重和。如果任一个叶子结点的样本权重低于某一个阈值,也会放弃此次分裂。这涉及到一个超参数:最小样本权重和,是指如果一个叶子节点包含的样本数量太少也会放弃分裂,防止树分的太细。
对于不平衡的数据集,例如用户的购买行为,肯定是极其不平衡的,这对XGBoost的训练有很大的影响,XGBoost有两种自带的方法来解决:
第一种,如果你在意AUC,采用AUC来评估模型的性能,那你可以通过设置scale_pos_weight来平衡正样本和负样本的权重。例如,当正负样本比例为1:10时,scale_pos_weight可以取10;
第二种,如果你在意概率(预测得分的合理性),你不能重新平衡数据集(会破坏数据的真实分布),应该设置max_delta_step为一个有限数字来帮助收敛(基模型为LR时有效)
在目标函数中增加了正则项:使用叶子结点的数目和叶子结点权重的L2模的平方,控制树的复杂度。
在结点分裂时,定义了一个阈值,如果分裂后目标函数的增益小于该阈值,则不分裂。
当引入一次分裂后,重新计算新生成的左、右两个叶子结点的样本权重和。如果任一个叶子结点的样本权重低于某一个阈值(最小样本权重和),也会放弃此次分裂。
XGBoost 先从顶到底建立树直到最大深度,再从底到顶反向检查是否有不满足分裂条件的结点,进行剪枝。
XGBoost在训练前预先将特征按照特征值进行了排序,并存储为block结构,以后在结点分裂时可以重复使用该结构。
因此,可以采用特征并行的方法利用多个线程分别计算每个特征的最佳分割点,根据每次分裂后产生的增益,最终选择增益最大的那个特征的特征值作为最佳分裂点。
如果在计算每个特征的最佳分割点时,对每个样本都进行遍历,计算复杂度会很大,这种全局扫描的方法并不适用大数据的场景。XGBoost还提供了一种直方图近似算法,对特征排序后仅选择常数个候选分裂位置作为候选分裂点,极大提升了结点分裂时的计算效率。
我们采用三种方法来评判XGBoost模型中特征的重要程度:
首先需要初始化一些基本变量,例如:
max_depth = 5
min_child_weight = 1
gamma = 0
subsample, colsample_bytree = 0.8
scale_pos_weight = 1
(1) 确定learning rate和estimator的数量
learning rate可以先用0.1,用cv来寻找最优的estimators
(2) max_depth和 min_child_weight
我们调整这两个参数是因为,这两个参数对输出结果的影响很大。我们首先将这两个参数设置为较大的数,然后通过迭代的方式不断修正,缩小范围。
max_depth,每棵子树的最大深度,check from range(3,10,2)。
min_child_weight,子节点的权重阈值,check from range(1,6,2)。
如果一个结点分裂后,它的所有子节点的权重之和都大于该阈值,该叶子节点才可以划分。
(3) gamma
也称作最小划分损失min_split_loss,check from 0.1 to 0.5,指的是,对于一个叶子节点,当对它采取划分之后,损失函数的降低值的阈值。
如果大于该阈值,则该叶子节点值得继续划分
如果小于该阈值,则该叶子节点不值得继续划分
(4) subsample, colsample_bytree
subsample是对训练的采样比例
colsample_bytree是对特征的采样比例
both check from 0.6 to 0.9
(5) 正则化参数
alpha 是L1正则化系数,try 1e-5, 1e-2, 0.1, 1, 100
lambda 是L2正则化系数
(6) 降低学习率
降低学习率的同时增加树的数量,通常最后设置学习率为0.01~0.1
当出现过拟合时,有两类参数可以缓解:
第一类参数:用于直接控制模型的复杂度。包括max_depth,min_child_weight,gamma 等参数
第二类参数:用于增加随机性,从而使得模型在训练时对于噪音不敏感。包括subsample,colsample_bytree
还有就是直接减小learning rate,但需要同时增加estimator 参数。
对存在缺失值的特征,一般的解决方法是:
离散型变量:用出现次数最多的特征值填充;
连续型变量:用中位数或均值填充;
一些模型如SVM和KNN,其模型原理中涉及到了对样本距离的度量,如果缺失值处理不当,最终会导致模型预测效果很差。
而树模型对缺失值的敏感度低,大部分时候可以在数据缺失时时使用。原因就是,一棵树中每个结点在分裂时,寻找的是某个特征的最佳分裂点(特征值),完全可以不考虑存在特征值缺失的样本,也就是说,如果某些样本缺失的特征值缺失,对寻找最佳分割点的影响不是很大。
XGBoost对缺失数据有特定的处理方法,详情参考上面。
因此,对于有缺失值的数据在经过缺失处理后:
当数据量很小时,优先用朴素贝叶斯
数据量适中或者较大,用树模型,优先XGBoost
数据量较大,也可以用神经网络
避免使用距离度量相关的模型,如KNN和SVM
细节
(1)树生长策略:XGB采用level-wise的分裂策略,LGB采用leaf-wise的分裂策略。XGB对每一层所有节点做无差别分裂,但是可能有些节点增益非常小,对结果影响不大,带来不必要的开销。Leaf-wise是在所有叶子节点中选取分裂收益最大的节点进行的,但是很容易出现过拟合问题,所以需要对最大深度做限制 。
(2)分割点查找算法:XGB使用特征预排序算法,LGB使用基于直方图的切分点算法,其优势如下:
减少内存占用,比如离散为256个bin时,只需要用8位整形就可以保存一个样本被映射为哪个bin(这个bin可以说就是转换后的特征),对比预排序的exact greedy算法来说(用int_32来存储索引+ 用float_32保存特征值),可以节省7/8的空间。
计算效率提高,预排序的Exact greedy对每个特征都需要遍历一遍数据,并计算增益。而直方图算法在建立完直方图后,只需要对每个特征遍历直方图即可。
LGB还可以使用直方图做差加速,一个节点的直方图可以通过父节点的直方图减去兄弟节点的直方图得到,从而加速计算
但实际上xgboost的近似直方图算法也类似于lightgbm这里的直方图算法,为什么xgboost的近似算法比lightgbm还是慢很多呢?
xgboost在每一层都动态构建直方图, 因为xgboost的直方图算法不是针对某个特定的feature,而是所有feature共享一个直方图(每个样本的权重是二阶导),所以每一层都要重新构建直方图,而lightgbm中对每个特征都有一个直方图,所以构建一次直方图就够了。
(3)支持离散变量:无法直接输入类别型变量,因此需要事先对类别型变量进行编码(例如独热编码),而LightGBM可以直接处理类别型变量。
(4)缓存命中率:XGB使用Block结构的一个缺点是取梯度的时候,是通过索引来获取的,而这些梯度的获取顺序是按照特征的大小顺序的,这将导致非连续的内存访问,可能使得CPU cache缓存命中率低,从而影响算法效率。而LGB是基于直方图分裂特征的,梯度信息都存储在一个个bin中,所以访问梯度是连续的,缓存命中率高。
(5)LightGBM 与 XGboost 的并行策略不同:
特征并行 :LGB特征并行的前提是每个worker留有一份完整的数据集,但是每个worker仅在特征子集上进行最佳切分点的寻找;worker之间需要相互通信,通过比对损失来确定最佳切分点;然后将这个最佳切分点的位置进行全局广播,每个worker进行切分即可。XGB的特征并行与LGB的最大不同在于XGB每个worker节点中仅有部分的列数据,也就是垂直切分,每个worker寻找局部最佳切分点,worker之间相互通信,然后在具有最佳切分点的worker上进行节点分裂,再由这个节点广播一下被切分到左右节点的样本索引号,其他worker才能开始分裂。二者的区别就导致了LGB中worker间通信成本明显降低,只需通信一个特征分裂点即可,而XGB中要广播样本索引。
数据并行 :当数据量很大,特征相对较少时,可采用数据并行策略。LGB中先对数据水平切分,每个worker上的数据先建立起局部的直方图,然后合并成全局的直方图,采用直方图相减的方式,先计算样本量少的节点的样本索引,然后直接相减得到另一子节点的样本索引,这个直方图算法使得worker间的通信成本降低一倍,因为只用通信以此样本量少的节点。XGB中的数据并行也是水平切分,然后单个worker建立局部直方图,再合并为全局,不同在于根据全局直方图进行各个worker上的节点分裂时会单独计算子节点的样本索引,因此效率贼慢,每个worker间的通信量也就变得很大。
投票并行(LGB):当数据量和维度都很大时,选用投票并行,该方法是数据并行的一个改进。数据并行中的合并直方图的代价相对较大,尤其是当特征维度很大时。大致思想是:每个worker首先会找到本地的一些优秀的特征,然后进行全局投票,根据投票结果,选择top的特征进行直方图的合并,再寻求全局的最优分割点。
原理