本站原创文章,转载请说明来自
《老饼讲解-机器学习》
www.bbbdata.com
本文讲解sklearn决策树中特征权重feature_importances是什么,
并根据feature_importances的计算逻辑,
用代码重现sklearn的feature_importances计算。
01. feature_importances是什么
clf.feature_importances是各个特征的重要性指标,
即各个特征对模型的贡献性占比,
(这里的clf是sklearn.tree.DecisionTreeClassifier返回的对象)
例如, feature_importances=[0 , 0, 0.05, 0.95]
则代表
第1、2个对象对模型的贡献为0,
第3个特征贡献度为5%
第4个特征贡献度为95%
02. 计算逻辑与流程
那么,feature_importances是怎么计算出来的呢?
它的推导与计算逻辑如下:
定义特征对单个节点分裂带来的贡献
为不纯度的降低量:
这里的impurity为不纯度评估值 (gini /熵)
如果考虑节点的权重,则为
特征的权重为使用该特征分裂节点的贡献总和
将所有特征的权重归一化后即得到特征权重:
计算流程如下
1. 计算每个分枝节点分枝带来的不纯度的降低量。
2. 把节点的不纯度降低量累加到对应的特征贡献上(节点分裂使用的特征)
3. 计算完所有节点后,对特征贡献作归一化即得到特征权重。
03. 代码实现
下面我们按以上计算逻辑,
编写代码计算feature_importances,
再与sklearn给出的feature_importances作比较,
验证以上逻辑就是sklearn中的逻辑。
代码如下
# -*- coding: utf-8 -*-
from sklearn.datasets import load_iris
from sklearn import tree
import numpy as np
#----------------数据准备----------------------------
iris = load_iris() # 加载数据
#---------------模型训练---------------------------------
clf = tree.DecisionTreeClassifier(random_state=0,max_depth=3)
clf = clf.fit(iris.data, iris.target)
#---------------提取模型结构数据--------------------------
children_left = clf.tree_.children_left # 左节点编号
children_right = clf.tree_.children_right # 右节点编号
feature = clf.tree_.feature # 分割的变量
threshold = clf.tree_.threshold # 分割阈值
impurity = clf.tree_.impurity # 不纯度(gini)
n_node_samples = clf.tree_.n_node_samples # 样本个数
value = clf.tree_.value # 样本分布
n_features = clf.tree_.n_features # 特征个数
total_n = n_node_samples[0] # 样本总个数
feature_importances = np.zeros(n_features) # 初始化特征权重全为0
for i in range(len(feature)): # 逐节点计算
use_feature = feature[i] # 当前节点使用的特征
if(use_feature<0): # 如果是叶子,则跳过
continue
left_idx = children_left[i] # 左节点索引
right_idx = children_right[i] # 右节点索引
left_impurity = impurity[left_idx] # 左节点不纯度
right_impurity = impurity[right_idx] # 右节点不纯度
node_impurity = impurity[i] # 节点不纯度
node_n = n_node_samples[i] # 节点样本数
left_n = n_node_samples[left_idx] # 左节点样本数
right_n = n_node_samples[right_idx] # 右节点样本数
importances = (node_n/total_n)*( node_impurity - (left_n/node_n)*left_impurity - (right_n/node_n)*right_impurity)
feature_importances[use_feature] += importances # 将权重累计到对应的变量上
feature_importances = feature_importances/feature_importances.sum() # 归一化
#---------------打印结果------------------------------------
print("模型计算结果feature_importances:",clf.feature_importances_)
print("自行计算结果feature_importances:",feature_importances)
注意:如果样本是带权重的,则计算过程中应用 样本权重个数 替代 样本个数。
代码运行结果如下:
模型计算结果feature_importances: [0. 0. 0.05393633 0.94606367]
自行计算结果feature_importances: [0. 0. 0.05393633 0.94606367]
从结果可见,自行计算与模型输出结果一致
End