python get score gain_机器学习的特征重要性究竟是怎么算的
最近将主流模型的sklearn的代码撸了一遍,特别是计算特征重要性这块仔仔细细了解了一番;常用算法中xgboost、gbdt、randomforest、tree等都可以输出特征的重要性评分,下面着重记录xgboost和gbdt特征重要性计算过程,randomforest和gbdt差不多,就不赘述了。
1.xgboost
1.简介
xgboost是当下流行的boosting算法,基学习器可以是gbtree也可以是gbliner
当基学习器是gbtree时,可以计算特征重要性;
在基础的xgboost模块中,计算特征重要性调用get_score()
在xgboost的sklearn API中,计算特征重要性调用feature_importance_;
feature_importance_依然派生于get_score(),所以查看xgboost的get_score()源码就可知其所以然;
2.url:https://github.com/zengfanxi/xgboost/blob/master/python-package/xgboost/core.pyget_score有两个参数,fmap是一个包含特征名称映射关系的txt文档; importance_type指importance的计算类型;可取值有5个:weight:权重(某特征在整个树群节点中出现的次数,出现越多,价值就越高)
gain:(某特征在整个树群作为分裂节点的信息增益之和再除以某特征出现的频次)
total_gain(同上,代码中有介绍,这里total_gain就是gain)
cover和total_cover
cover比较复杂,python文档未做解释,其实是指某特征节点样本的二阶导数和再除以某特征出现的 我在xgboost R API文档中找到了部分解释: https://github.com/dmlc/xgboost/blob/f5659e17d5200bd7471a2e735177a81cb8d3012b/R-package/man/xgb.plot.tree.Rd
代码中频繁提到通过get_dump获取树规则,举个例子看看什么是树规则:
trees = bst.get_dump(with_stats=True)
for tree in trees:
print(tree)
# 以下输出了2次迭代的决策树规则,规则内包含量特征名、gain和cover,
# 源码就是提取上述3个变量值进行计算特征重要性
[out]:
0:[inteval<1] yes=1,no=2,missing=1,gain=923.585938,cover=7672
1:[limit<9850] yes=3,no=4,missing=3,gain=90.4335938,cover=6146.5
3:leaf=-1.86464596,cover=5525.25
4:leaf=-1.45520294,cover=621.25
2:[days<3650] yes=5,no=6,missing=5,gain=164.527832,cover=1525.5
5:leaf=-1.36227047,cover=598
6:leaf=-0.688206792,cover=927.5
0:[days<7850] yes=1,no=2,missing=1,gain=528.337646,cover=4162.56592
1:[frequency<4950] yes=3,no=4,missing=3,gain=64.1247559,cover=2678.6853
3:leaf=-0.978122056,cover=1715.49646
4:leaf=-0.653981686,cover=963.188965
2:[interval<4] yes=5,no=6,missing=5,gain=179.725327,cover=1483.88074
5:leaf=-0.256728679,cover=1280.68018
6:leaf=0.753442943,cover=203.200531
这里是源码:
# 当重要性类型选择“weight”时:
if importance_type == 'weight':
# get_dump用以从模型中打印输出所有树的规则信息
trees = self.get_dump(fmap, with_stats=False)
fmap = {}
# 以下for循环用以从所有树规则中提取出特征名称
for tree in trees:
for line in tree.split('\n'):
arr = line.split('[')
if len(arr) == 1:
continue
fid = arr[1].split(']')[0].split('
# 以下语句利用if判断统计所有树规则中每个特征出现的频次
# 即每个特征在分裂时候被利用的次数
if fid not in fmap:
fmap[fid] = 1
else:
fmap[fid] += 1
return fmap
else:
# 通过以下代码知道importance_type选择total_gain时其实就是gain;
# 选择total_cover时也等同于cover
average_over_splits = True
if importance_type == 'total_gain':
importance_type = 'gain'
average_over_splits = False
elif importance_type == 'total_cover':
importance_type = 'cover'
average_over_splits = False
# 还是先打印输出所有树规则信息
trees = self.get_dump(fmap, with_stats=True)
importance_type += '='
fmap = {}
gmap = {}
for tree in trees:
for line in tree.split('\n'):
arr = line.split('[')
if len(arr) == 1:
continue
fid = arr[1].split(']')
# 该步计算g的时候利用了importance_type参数
# 当importance_type="gain"时,提取树规则中的gain值
# 当importance_type="cover"时,提取树规则中的cover值
g = float(fid[1].split(importance_type)[1].split(',')[0])
# fid和参数weight时候的fmap是一样的,其实都是从树规则中提取到的特征名称列表
fid = fid[0].split('
# 这步if操作,涉及两个统计量
# 一是每个特征在所有树规则中出现的频次
# 二是每个特征在所有树节点上的信息增益之和
if fid not in fmap:
fmap[fid] = 1
gmap[fid] = g
else:
fmap[fid] += 1
gmap[fid] += g
# 将特征重要性求均值得到最终的重要性统计量,具体方法是:
# 当importance_type ="gain":a特征重要性为a总的信息增益和除以树规则中a特征出现的总频次
# 当importance_type = "cover时",a特征重要性为a总的cover和除以树规则中a特征出现的总频次
if average_over_splits:
for fid in gmap:
gmap[fid] = gmap[fid] / fmap[fid]
注意,原始的get_score()方法只是输出按照weight、gain、cover计算的统计值,还没有换算成百分比形式,所以走到这里还不是真正的重要性得分!
所以继续查看xgboost的sklearn API中feature_importance_方法: 很容易发现,feature_importance_中做了一个特征归一化,将重要性统计量转化成量百分比形式,分母其实就是所有特征的重要性统计量之和。
def feature_importances_(self):
if getattr(self, 'booster', None) is not None and self.booster != 'gbtree':
raise AttributeError('Feature importance is not defined for Booster type {}'
.format(self.booster))
b = self.get_booster()
score = b.get_score(importance_type=self.importance_type)
all_features = [score.get(f, 0.) for f in b.feature_names]
all_features = np.array(all_features, dtype=np.float32)
# 核心就是最后一步,有个归一化的过程,将重要性统计量转化成百分比
return all_features / all_features.sum()
另外注意,从构造函数中发现,xgboost sklearn API在计算特征重要性的时候默认importance_type="gain",而原始的get_score方法默认importance_type="weight"
def __init__(self, max_depth=3, learning_rate=0.1, n_estimators=100,
verbosity=1, silent=None, objective="reg:linear", booster='gbtree',
n_jobs=1, nthread=None, gamma=0, min_child_weight=1,
max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1,
colsample_bynode=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
base_score=0.5, random_state=0, seed=None, missing=None,
# 在这一步进行了声明
importance_type="gain", **kwargs):
2.gbdt
首先找到BaseGradientBoosting类,得到feature_importances_方法源码如下:
def feature_importances_(self):
"""Return the feature importances (the higher, the more important the
feature).
Returns
-------
feature_importances_ : array, shape = [n_features]
"""
self._check_initialized()
total_sum = np.zeros
# 这一步for循环从self.estimators_遍历每个回归树
# 主类的estimators_方法用以输出gbdt训练过程中建立的决策树群
for stage in self.estimators_:
# 针对每个决策树子树,分别调用feature_importances_方法
# 这说明决策树群中每个子树都对应一套特征重要性
# 也说明BaseGradientBoosting的feature_importances_方法只是对决策树的feature_importances_进行变换,并非最原始的逻辑
stage_sum = sum(tree.feature_importances_
for tree in stage) / len(stage)
# 这里将每棵树的特征重要性数组合并加总成一个数组
total_sum += stage_sum
# 这里将合并后的数组值除以树的个数,可以看作是每个树平均的特征重要性情况
importances = total_sum / len(self.estimators_)
return importances
既然没有得到想要的,继续从tree中找feature_importances_源码,发现tree的feature_importances_来自于tree_.compute_feature_importances()方法:
cpdef compute_feature_importances(self, normalize=True):
"""Computes the importance of each feature (aka variable)."""
cdef Node* left
cdef Node* right
cdef Node* nodes = self.nodes
cdef Node* node = nodes
cdef Node* end_node = node + self.node_count
cdef double normalizer = 0.
cdef np.ndarray[np.float64_t, ndim=1] importances
importances = np.zeros((self.n_features,))
cdef DOUBLE_t* importance_data = importances.data
with nogil:
# 在计算impurity时,while和if用以过滤掉决策树中的根节点和叶子节点
while node != end_node:
if node.left_child != _TREE_LEAF:
left = &nodes[node.left_child]
right = &nodes[node.right_child]
# 遍历每个节点,该节点对应分裂特征重要性统计量=分裂前impurity减去分裂后左右二叉树impurity之和
# 计算impurity的差值时,每个impurity都乘以对应权重(分支的样本数)
# 一个特征在树中可以被用来多次分裂,基于上一步的数据,等同于这里按照特征groupby后对其重要性统计量求和
importance_data[node.feature] += (
node.weighted_n_node_samples * node.impurity -
left.weighted_n_node_samples * left.impurity -
right.weighted_n_node_samples * right.impurity)
node += 1
# 每个特征的重要性统计量初一根节点样本总数,做了下平均
importances /= nodes[0].weighted_n_node_samples
# 各特征重要性统计量最重要转化成百分比度量
# 该步将各特征统计量分别除以统计量总和,归一化操作
# 转化成百分比就得到了我们看到的特征重要性
if normalize:
normalizer = np.sum(importances)
if normalizer > 0.0:
# Avoid dividing by zero (e.g., when root is pure)
importances /= normalizer
return importances
看到这里,应该存在一个疑问,那就是gbdt是根据分裂前后节点的impurity减少量来评估特征重要性,那么impurity的计算标准是什么? 这个问题源码中的_criterion.pyx脚本中有回答, criterion分裂标准有:Entropy:熵,适用分类树
Gini:基尼系数,适用分类树
MSE:均方误差,适用回归树
MAE:平均绝对误差,适用回归树
gbdt中的树全部是回归树,所以impurity计算和节点的分裂标准是MSE或MAE,criterion参数在模型训练时设置!
python get score gain_机器学习的特征重要性究竟是怎么算的相关推荐
- Python每日一记42机器学习中特征重要性feature_importances_
在进行机器学习算法中,我们常用的算法就像下面的代码形式类型 经历导入数据-预处理-建模-得分-预测 但是总觉得少了点什么,虽然我们建模的目的是进行预测,但是我们想要知道的另一个信息是变量的重要性,在线 ...
- 机器学习_特征重要性之Shapely Value
很多时候我们输出的特征重要性gain值和cover值不一致,会导致些许困惑(到底那个特征最为重要,那个特征重要性要靠前).所以,我们考虑用shapely value 来衡量特征的重要性,它即考虑了特征 ...
- python get score gain_什么是“熵和信息增益”?(What is “entropy and information gain”?)...
什么是"熵和信息增益"?(What is "entropy and information gain"?) 我正在读这本书( NLTK ),令人困惑. 熵被定义 ...
- Spark 和 Python.sklearn:使用随机森林计算 feature_importance 特征重要性
前言 在使用GBDT.RF.Xgboost等树类模型建模时,往往可以通过feature_importance 来返回特征重要性,本文以随机森林为例介绍其原理与实现.[ 链接:机器学习的特征重要性究竟是 ...
- 如何用Python计算特征重要性?
特征重要性评分是一种为输入特征评分的手段,其依据是输入特征在预测目标变量过程中的有用程度. 特征重要性有许多类型和来源,尽管有许多比较常见,比如说统计相关性得分,线性模型的部分系数,基于决策树的特征重 ...
- python随机森林变量重要性_随机森林如何评估特征重要性【机器学习面试题详解】...
今天爱分享给大家带来随机森林如何评估特征重要性[机器学习面试题详解],希望能够帮助到大家. 解析: 衡量变量重要性的方法有两种,Decrease GINI 和 Decrease Accuracy: 1 ...
- 【Python】Pandas/Sklearn进行机器学习之特征筛选,有效提升模型性能
今天小编来说说如何通过pandas以及sklearn这两个模块来对数据集进行特征筛选,毕竟有时候我们拿到手的数据集是非常庞大的,有着非常多的特征,减少这些特征的数量会带来许多的好处,例如 提高预测的精 ...
- 机器学习如何计算特征的重要性_机器学习之特征工程
特征选择是特征工程中的一个子集,从所有的特征中,选择有意义的,对模型有帮助的特征,以避免将所有特征中对模型没作用的特征导入模型去训练,消耗不必要的计算资源.更正式地说,给定n个特征,我们搜索其中包括k ...
- 机器学习模型可解释性进行到底——特征重要性(四)
文章目录 1 四种全局可解释的方法论 1.1 过滤法 1.1.1 方差过滤方差过滤 1.1.2 相关性过滤 1.2 嵌入法 1.2.1 SelectFromModel - 筛选特征 1.2.2 Per ...
最新文章
- CSS3实现图形曲线阴形和翘边阴影
- Qt工作笔记-QTreeWidgetItem中type的基本用法
- 知方可补不足~UPDLOCK更新锁的使用
- AngularJS自定义指令–隔离范围教程
- 教你React Native使用fetch实现图片上传
- NYOJ 93 汉诺塔(三) 【栈的简单应用】
- SQLite数据库的使用——利用命令行或Navicat Premium创建数据库
- 软件设计师--判定覆盖,判定条件覆盖,条件组合覆盖--一个栗子
- SNS过早收费扼杀用户成长
- 四象限时间管理有多好用?
- 在线计算机容量单位换算,体积换算 | 容量计量单位转换器 —在线工具
- 2020大疆校招嵌入式B卷编程题
- 利用报废主板制作SPD刷内存编程器座子
- 老男孩python培训课件
- 身份证OCR识别工作原理及流程
- 网页设计常见的设计标准尺寸以及注意事项
- UVa11400 Lighting System Design
- 一个例题:浮动引起元素变成行内块元素-display:inline-block
- 工业相机的传感器靶面大小
- 计算机与信息科学杂志,计算机、控制与信息技术重要期刊网址
热门文章
- 2021中国大学MOOC 机器学习(温州大学) 最新中国大学MOOC满分章节测试答案
- IterNet: Retinal Image Segmentation Utilizing Structural Redundancy in Vessel Networks
- 模拟地铁自动售票系统C语言,基于PLC的地铁自动售票机控制系统设计.doc
- 湖仓一体电商项目(一):项目背景和架构介绍
- 2021年安全员-B证(广西省-2021版)考试技巧及安全员-B证(广西省-2021版)
- (转)eclipse 打开pom.xml文件很慢 设置pom.xml打开方式
- 教你快速爬取哔哩哔哩整部番剧的视频弹幕
- kal安装了tim,无法显示图片咋办
- 【财富空间】其实,硅谷最会玩的是“失败”
- 2021多益网络春季校园招聘游戏研发笔试题(回忆版)