老饼讲解-机器学习 机器学习 神经网络 深度学习
决策树

决策树的特征权重feature_importances

作者 : 老饼 发表日期 : 2022-06-26 09:52:42 更新日期 : 2022-08-20 01:15:36
本站原创文章,转载请说明来自《老饼讲解-机器学习》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 








联系老饼