1、Lightgbm如何处理类别特征
one-hot的弊端:
参考:https://www.zhihu.com/people/insulator/answers
one-hot编码是处理类别特征的一个通用方法,然而在树模型中,这可能并不一定是一个好的方法,尤其当类别特征中类别个数很多的情况下。主要的问题是:
-
可能无法在这个类别特征上进行切分(即浪费了这个特征)。使用one-hot编码的话,意味着在每一个决策节点上只能使用one vs rest(例如是不是狗,是不是猫等)的切分方式。当类别值很多时,每个类别上的数据可能会比较少,这时候切分会产生不平衡,这意味着切分增益也会很小(比较直观的理解是,不平衡的切分和不切分没有区别)。
-
会影响决策树的学习。因为就算可以在这个类别特征进行切分,也会把数据切分到很多零碎的小空间上,如图1左边所示。而决策树学习时利用的是统计信息,在这些数据量小的空间上,统计信息不准确,学习会变差。但如果使用如图1右边的分裂方式,数据会被切分到两个比较大的空间,进一步的学习也会更好。这样才能充分的挖掘该维特征所包含的信息,找到最优的分割策略。
在决策树上怎么用类别特征
LGBM采用了Many vs many的切分方式,实现了类别特征的最优切分。用Lightgbm可以直接输入类别特征,并产生如图1右边的效果。在1个k维的类别特征中寻找最优切分,朴素的枚举算法的复杂度是O(2^k),而LGBM实现了O(klogk)的算法。
二、 算法流程:
1. 建立直方图
对于连续值:先把特征取值从连续值转化成了离散值,也就是对每个特征的取值做个分段函数;对于离散化后的连续值特征 & 其他本来就是离散值的特征:统计该特征下每一种离散值出现的次数,并从高到低排序,并过滤掉出现次数较少的特征值, 然后为每一个特征值,建立一个bin容器。
对于该过程:算法图为下图1,case为下图2,左边#features(红框)、#data(绿框)即为表格中的数据,所以对应右侧的#features = 4,#bins(每个feature都有其对应的bin)中的每个#bin分别为:对于性别特征:#bin = 2(两个离散值);对于年龄特征:#bin = 离散化后的特征个数;对于手机特征:#bin = 3,对于身高特征(已经进行了预处理离散化)#bin = 3直方图算法有几个需要注意的地方:
- 使用bin替代原始数据相当于增加了正则化;
- 使用bin意味着很多数据的细节特征被放弃了,相似的数据可能被划分到相同的桶中,这样的数据之间的差异就消失了;
- bin数量选择决定了正则化的程度,bin越少惩罚越严重,欠拟合风险越高。
2. 枚举分割点
在枚举分割点之前,先把直方图按每个类别的均值进行排序;然后按照均值的结果依次枚举最优分割点。从下图1可以看到,Sum(y) / Count(y)为类别的均值。当然,这个方法很容易过拟合,所以LightGBM里面还增加了很多对于这个方法的约束和正则化如身高特征(高、中、低三个枚举值):分别计算 Sum(y) / Count(y),按照均值的结果依次枚举最优分割点;为什么这样的顺序枚举呢?直观的理解是:sum / count 越低,则代表该特征对应的Y值种类数越多,也就是越杂乱,越需要分割,比如高特征两个data样本,两种Y,中特征三个data样本,两种Y,低特征一个data样本,一种Y(不需要分割),这样分割得到的信息增益最大,效率最高
3. 计算分类阈值
- 首先(最外面的for循环),对于当前模型的每个叶子节点,需要遍历所有的特征(# features),来找到增益最大的特征及其划分值,以此来分裂该叶子节点。gbdt会训练多个树模型,这个举例可能是其中任何一个模型吧。
- 然后(在第二个for循环中)对于每个特征(feature),首先为其创建一个直方图,这个直方图存储了两类信息,分别是每个bin中样本的梯度之和( 等同于sum(Y) ),还有就是每个bin中样本数量( 等同于 count(Y) )
- 插入一个解释:( S_L)是当前分裂bin左边所有bin的集合,对比理解(S_R),那么(S_P)其中的P就是parent的意思,就是父节点
- 遍历所有样本,累积上述的两类统计值到样本所属的 bin 中;接着遍历所有bin,分别以当前 bin 作为分割点,累加其左边的 bin 至当前 bin 的梯度和(SL)以及样本数量(nL),并与父节点上的总梯度和(Sp)以及总样本数量(np)相减,得到右边所有bin的梯度和(SR)以及样本数量(nR),带入公式计算出增益,一句话解释就是(右=父-左)。在遍历过程中取最大的增益,以此时的特征和bin的特征值作为分裂节点的特征和分裂特征取值。(直方图做差加速)
4. 带深度限制的 Leaf-wise 算法
LightGBM采用Leaf-wise的增长策略,该策略每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同Level-wise相比,Leaf-wise的优点是:在分裂次数相同的情况下,Leaf-wise可以降低更多的误差,得到更好的精度;Leaf-wise的缺点是:可能会长出比较深的决策树,产生过拟合。因此LightGBM会在Leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合
三、优缺点
优点:
- 首先,最明显就是内存消耗的降低,直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值,而这个值一般用 8 位整型存储就足够了,内存消耗可以降低为原来的1/8。
- 然后在计算上的代价也大幅降低,预排序算法每遍历一个特征值就需要计算一次分裂的增益,而直方图算法只需要计算 k 次(#bins)(k 可以认为是常数),时间复杂度从O(#样本数*#特征数)优化到O(k*#特征数)。
缺点:
- 预处理能够忽略零值特征,减少训练代价;而直方图不能对稀疏进行优化,只是计算累加值(累加梯度和样本数)。但是,LightGBM对稀疏进行了优化:只用非零特征构建直方图。
LightGBM为何使用直方图这种比较粗的分割节点方法,还能达到比较好的效果
- 虽然分割的精度变差了,但是对最后结果的影响不是很大,主要由于决策树是弱模型, 分割点是不是精确并不是太重要 ;较粗的分割点也有正则化的效果,可以有效地防止过拟合;即使单棵树的训练误差比精确分割的算法稍大,但在梯度提升(Gradient Boosting)的框架下没有太大的影响。