失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > [机器学习] 树模型(xgboost lightgbm)特征重要性原理总结

[机器学习] 树模型(xgboost lightgbm)特征重要性原理总结

时间:2023-04-23 02:15:37

相关推荐

[机器学习] 树模型(xgboost lightgbm)特征重要性原理总结

在使用GBDT、RF、Xgboost等树类模型建模时,往往可以通过 feature_importance 来返回特征重要性,各模型输出特征重要性的原理与方法

一 计算特征重要性方法

首先,目前计算特征重要性计算方法主要有两个方面:

1.1 训练过程中计算

训练过程中通过记录特征的分裂总次数、总/平均信息增益来对特征重要性进行量化。例如实际工程中我们会用特征在整个GBDT、XGBoost里面被使用的次数或者带来的总/平均信息增益来给特征重要度打分,最后进行排序。由于本身Ensemble模型在选择特征分裂时带有一定随机性,一般会跑多个模型然后把特征重要性求平均后排序。

作为单个决策树模型,在模型建立时实际上是寻找到某个特征合适的分割点。这个信息可以作为衡量所有特征重要性的一个指标。

基本思路如下:

如果一个特征被选为分割点的次数越多,那么这个特征的重要性就越强。这个理念可以被推广到集成算法中,只要将每棵树的特征重要性进行简单的平均即可。

分别根据特征1和特征4进行分割,显然x1出现的次数最多,这里不考虑先分割和后分割的情况,只考虑每次分割属性出现的次数。

计算得:

x1的特征重要度:出现在2棵树上,两棵树一共分裂了6次,x1出现了3次。

x1特征重要度 = 3/6 = 1/2

x2的特征重要度= 4/6 = 2/3

x3的特征重要度= 3/6 = 1/2

x4的特征重要度: 出现在1棵树上,一个树分裂了3次,x4出现了1次。

x4的特征重要度= 1/3

根据特征重要度进行特征选择。

1.2 训练后使用OOB(Out of Bag)数据计算

第二种方式是训练好模型之后,用Out of Bag(或称Test)数据进行特征重要性的量化计算。具体来说,先用训练好的模型对OOB数据进行打分,计算出AUC或其他业务定义的评估指标;接着对OOB数据中的每个特征:

(1)随机shuffle当前特征的取值;

(2)重新对当前数据进行打分,计算评估指标;

(3)计算指标变化率

按照上面方式,对每个特征都会得到一个变化率,最后按照变化率排序来量化特征重要性。

延伸到 DNN 对特征重要性判定:

DNN不像Boosting这类模型那样存在所谓的分裂次数与信息增益,就需要使用第二种方式,对每个特征进行随机shuffle,观察模型指标的变化,最后按照变化率进行排序。比如AUC下滑率,下滑的越多说明当前这个指标越重要。当然,实际操作中需要结合业务经验先指定一个候选变量池,对这部分变量计算重要度,不然计算开销太大。

二. 树模型特征重要性判定

2.1 Random Foreast

袋外数据错误率(可参考OOB特征选择方法)基尼指数(和GBDT的方法相同)

随机森林特征重要性评定可参考:/zjuPeco/article/details/77371645?locationNum=7&fps=1

2.2 GBDT

基尼指数

在sklearn中,GBDT和RF的特征重要性计算方法是相同的,都是基于单棵树计算每个特征的重要性,探究每个特征在每棵树上做了多少的贡献,再取个平均值。

2.3 XGBoost

根据结构分数的增益情况计算出来选择哪个特征作为分割点,而某个特征的重要性就是它在所有树中出现的次数之和。也就是说一个属性越多的被用来在模型中构建决策树,它的重要性就相对越高

xgboost实现中Booster类get_score方法输出特征重要性,其中importance_type参数支持三种特征重要性的计算方法:

importance_type=weight(默认):the number of times a feature is used to split the data across all trees. 特征重要性使用特征在所有树中作为划分属性的次数。简单来说,就是在子树模型分裂时,用到的特征次数。这里计算的是所有的树importance_type=gain:is the average gain of splits which use the feature. 特征重要性使用特征在作为划分属性带来的平均增益。特征重要性使用特征在作为划分属性时loss平均的降低量。importance_type=cover:is the average coverage of splits which use the feature where coverage is defined as the number of samples affected by the split. 使用该特作为分割影响的平均样本数。——可以理解为被分到该节点的样本的二阶导数之和,而特征度量的标准就是平均的coverage值。特征重要性使用特征在作为划分属性时对样本的覆盖度。importance_type=total_gain: the total gain across all splits the feature is used in.importance_type=total_cover: the total coverage across all splits the feature is used in

使用场景

weight 将给予数值特征更高的值,因为它的变数越多,树分裂时可切割的空间越大。所以这个指标,会掩盖掉重要的枚举特征。

gain 用到了熵增的概念,它可以方便的找出最直接的特征。即如果某个特征的下的0,在label下全是0,则这个特征一定会排得靠前。

cover 对于枚举特征,会更友好。同时,它也没有过度拟合目标函数,不受目标函数的量纲影响。

举个例子

我们来做西瓜分类任务。西瓜有颜色、重量、声音、品种、产地等各类特征。其中,生活(业务)经验告诉我们,声音响的瓜甜。我们构建了这么一个模型,判断西瓜甜不甜。输出三类特征重要性。这时会看到一些矛盾的现象3。

weight解释下,声音这类枚举值特征并不会很靠前。反而是重量这类连续特征会靠前。为什么会这样子,是因为连续特征提供了更多的切分状态空间,这样的结果,势必导致它在树模型的分裂点上占据多个位置。与此同时,重要的枚举值特征靠后了。而且我们还能预见的是,同一个量纲下,上下界越大的特征,更有可能靠前。

如何解决这个矛盾点,那就是采用gain或者cover方法。因为声音这个特征,必然能带来更多的信息增益,减少系统的熵,所以它在信息增益数值上,一定是一个大值。在树模型的分类节点上,也一定是优先作为分裂点,靠近根部的。

在实践中,也会发现,gain排出来的顺序的头尾部值差距较大,这是因为信息增益计算时,后续的优化可能都不是一个量级。类似于神经网络在优化损失函数时,后续的量纲可能是十倍、百倍的差异。所以,综上而言,如果有下游业务方,更建议用cover的特征重要性计算方法。当然,如果是单纯的模型调优,gain能指出最重要的特征。这些特征,某些场景下还能总结成硬规则。

cover 的解释有点晦涩,在[R-package/man/xgb.plot.tree.Rd]有比较详尽的解释:

(/dmlc/xgboost/blob/f5659e17d5200bd7471a2e735177a81cb8d3012b/R-package/man/xgb.plot.tree.Rd)

the sum of second order gradient of training data classified to the leaf, if it is square loss, this simply corresponds to the number of instances in that branch. Deeper in the tree a node is, lower this metric will be。实际上coverage可以理解为被分到该节点的样本的二阶导数之和,而特征度量的标准就是平均的coverage值。

下面就结合这张图,解释下各指标含义:

1. weight: {‘f0’: 1, ‘f1’: 2}

在所有树中,某特征被用来分裂节点的次数,在本例中,可见分裂第1个节点时用到f0,分裂第2,3个节点时用到f1,所以weight_f0 = 1, weight_f1 = 2

2. total_cover: {‘f0’: 10.0, ‘f1’: 8.0}

第1个节点,f0被用来对所有10个样例进行分裂,之后的节点中f0没再被用到,所以f0的total_cover为10.0,此时f0 >= 0.855563045的样例有5个,落入右子树;

第2个节点,f1被用来对上面落入右子树的5个样例进行分裂,其中f1 >= -0.178257734的样例有3个,落入右子树;

第3个节点,f1被用来对上面落入右子树的3个样例进行分裂。

总结起来,f0在第1个节点分裂了10个样例,所以total_cover_f0 = 10,f1在第2、3个节点分别用于分裂5、3个样例,所以total_cover_f1 = 5 + 3 = 8。total_cover表示在所有树中,某特征在每次分裂节点时处理(覆盖)的所有样例的数量。

3. cover: {‘f0’: 10.0, ‘f1’: 4.0}

cover = total_cover / weight,在本例中,cover_f0 = 10 / 1,cover_f1 = 8 / 2 = 4.

4. total_gain: {‘f0’: 0.265151441, ‘f1’: 0.75000003}

在所有树中,某特征在每次分裂节点时带来的总增益,如果用熵或基尼不纯衡量分裂前后的信息量分别为i0和i1,则增益为(i0 - i1)。

5. gain: {‘f0’: 0.265151441, ‘f1’: 0.375000015}

gain就是特征用于分割的平均增益,gain = total_gain / weight,在本例中,gain_f0 = 0.265151441 / 1,gain_f1 = 75000003 / 2 = 375000015.

在平时的使用中,多用total_gain来对特征重要性进行排序。

2.4 Lightgbm

split:result contains numbers of times the feature is used in a mode (特征重要性使用特征在所有树中作为划分属性的次数)

gain:result contains total gains of splits which use the feature (使用该特征作为分割带来的总增益)

参考文献

树模型特征重要性评估方法_ep_mashiro的博客-CSDN博客_特征重要性评估/lz_peter/article/details/85010931

如果觉得《[机器学习] 树模型(xgboost lightgbm)特征重要性原理总结》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。