机器学习-专题详述

【原理】决策树的特征权重feature_importances

作者 : 老饼 发表日期 : 2022-06-26 09:52:42 更新日期 : 2024-06-30 10:16:05
本站原创文章,转载请说明来自《老饼讲解-机器学习》www.bbbdata.com



本文讲解sklearn决策树中特征权重feature_importances是什么

并根据feature_importances的计算逻辑,用代码重现sklearn的feature_importances计算




   01. 决策树的feature_importances是什么  





本节介绍决策树的feature_importances是什么,以及feature_importances的计算流程





         决策树的feature_importances是什么            


在sklearn中,使用clf=sklearn.tree.DecisionTreeClassifier()构建决策树后
可以通过clf.feature_importances查看各个特征的重要性指标,即各个特征对模型的贡献性占比
   例如, feature_importances=[0 , 0, 0.05, 0.95]
则代表第1、2个对象对模型的贡献为0,第3个特征贡献度为5% ,第4个特征贡献度为95% 
那么,feature_importances是怎么计算出来的呢?下面进行讲解





      决策树的feature_importances的公式推导       


在决策树中,变量的特征权重指的是该变量对降低树的不纯度所作的贡献
特征权重feature_importances的推导与计算逻辑如下:
 
先考虑单节点,特征对单个节点分裂带来的不纯度降低量(即贡献)为:  
  
这里的impurity为不纯度评估值 (gini/熵)
  
  
如果考虑节点的权重,则为
      
特征的权重为使用该特征分裂节点的贡献总和
将所有特征的权重归一化后即得到特征权重:





      决策树的feature_importances的计算流程       


feature_importances的计算流程如下:
 
1. 计算每个分枝节点分枝带来的不纯度的降低量。                                       
2. 把节点的不纯度降低量累加到对应的特征贡献上(节点分裂使用的特征) 
3. 计算完所有节点后,对特征贡献作归一化即得到特征权重。                      







   02. feature_importances的计算-代码实现   




本节讲解如何用代码自行计算决策树的feature_importances




    自行计算feature_importances     


下面我们按以上计算逻辑,编写代码计算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)  
注意:如果样本是带权重的,则计算过程中应用 样本权重个数 替代 样本个数




     代码运行结果     


代码运行结果如下:
 
从结果可见,自行计算与模型输出结果一致











 End 








联系老饼