数据分析 | 特征重要性分析 | 树模型、SHAP值法

news2024/11/26 13:44:09

前言

        在分析特征重要性的时候,相关性分析和主成分分析往往是比较简单的方法,相关性分析是通过计算特征与目标变量之间的相关系数来评估特征的重要性。它可以告诉我们特征和目标变量之间的线性关系程度,但对于非线性关系就无能为力了;主成分分析是一种降维技术,用于将高维特征数据转化为少数几个主成分。它可以帮助我们理解数据的主要变化模式,但却无法给出具体每个特征对目标变量的影响程度。

        本文基于集成学习的方法介绍另外两种可以分析特征重要性的方法:树模型、SHAP值法。


数据集

        本文使用的数据集为房价数据集,一共有20640个样本,8个特征,1个自变量,除了HouseAge是离散型变量,其余均为连续型变量。树模型分析重要性和贝叶斯优化时,均使用原始数据,SHAP值法时使用归一化后的数据。

原始数据节选

TPE过程贝叶斯优化超参数寻优

        集成学习中超参数设置一直是大问题,本文通过调用Optuna库进行TPE过程的贝叶斯优化,对三种树模型进行超参数寻优。代码如下:

import optuna
from sklearn.model_selection import KFold,cross_validate
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
import time
start_time = time.time()

# 读取数据
data = pd.read_csv(r'D:\2暂存文件\Sth with Py\重要性程度分析\data.csv')
X = data.iloc[:,[0, 1, 2, 3, 4, 5, 6, 7]]
y = data.iloc[:,8]

'''贝叶斯随机森林寻优'''
# 定义目标函数和参数空间
def optuna_objective(trial):
    # 定义参数空间
    n_estimators = trial.suggest_int('n_estimators', 10, 30, 1)
    max_depth = trial.suggest_int('max_depth', 10, 30, 1)
    max_features = trial.suggest_int('max_features', 10, 30, 1)

    # 定义评估器
    reg = RandomForestRegressor(n_estimators=n_estimators,
              max_depth=max_depth,
              max_features=max_features,
              random_state=1412,
              verbose=False,
              n_jobs=-1)

    # 定义交叉过程,输出负均方误差
    cv = KFold(n_splits=5, shuffle=True, random_state=1412)
    validation_loss = cross_validate(reg, X, y,
                                     scoring='neg_mean_squared_error',
                                     cv=cv,
                                     verbose=True,
                                     n_jobs=-1,
                                     error_score='raise')
    return np.mean(validation_loss['test_score'])

# 定义优化目标函数
def optimizer_optuna(n_trials):
    study = optuna.create_study(sampler=optuna.samplers.TPESampler(n_startup_trials=20, n_ei_candidates=30),
                                direction='maximize')
    study.optimize(optuna_objective, n_trials=n_trials, show_progress_bar=True)

    print('随机森林最优参数:\nbest_params:', study.best_trial.params,
          '随机森林最优得分:\nbest_score:', study.best_trial.values,
          '\n')

    return study.best_trial.params, study.best_trial.values

import warnings
warnings.filterwarnings('ignore',message='The objective has been evaluated at this point before trails')
optuna.logging.set_verbosity(optuna.logging.ERROR)
best_params, best_score = optimizer_optuna(100)

# 保存最优参数和最优得分到文件
with open(r'D:\2暂存文件\Sth with Py\重要性程度分析\随机森林贝叶斯优化结果.txt', 'w') as f:
    for key, value in best_params.items():
        f.write(f'{key}: {value}\n')
    f.write(f'Best Score: {best_score}\n')

'''贝叶斯决策树寻优'''
# 定义目标函数和参数空间
def optuna_objective(trial):
    # 定义参数空间
    max_depth = trial.suggest_int('max_depth', 10, 30, 1)
    min_samples_split = trial.suggest_int('min_samples_split',10,30,1)
    min_samples_leaf = trial.suggest_int('min_samples_leaf',10,30,1)
    max_features = trial.suggest_int('max_features', 10, 30, 1)

    # 定义评估器
    dtr = DecisionTreeRegressor(
        max_depth=max_depth,
        max_features=max_features,
        min_samples_split=min_samples_split,
        min_samples_leaf=min_samples_leaf,
        random_state=1412,)

    # 定义交叉过程,输出负均方误差
    cv = KFold(n_splits=5, shuffle=True, random_state=1412)
    validation_loss = cross_validate(dtr, X, y,
                                     scoring='neg_mean_squared_error',
                                     cv=cv,
                                     verbose=True,
                                     n_jobs=-1,
                                     error_score='raise')
    return np.mean(validation_loss['test_score'])

# 定义优化目标函数
def optimizer_optuna(n_trials):
    study = optuna.create_study(sampler=optuna.samplers.TPESampler(n_startup_trials=20, n_ei_candidates=30),
                                direction='maximize')
    study.optimize(optuna_objective, n_trials=n_trials, show_progress_bar=True)

    print('决策树最优参数:\nbest_params:', study.best_trial.params,
          '决策树最优得分:\nbest_score:', study.best_trial.values,
          '\n')

    return study.best_trial.params, study.best_trial.values

import warnings
warnings.filterwarnings('ignore',message='The objective has been evaluated at this point before trails')
optuna.logging.set_verbosity(optuna.logging.ERROR)
best_params, best_score = optimizer_optuna(100)

# 保存最优参数和最优得分到文件
with open(r'D:\2暂存文件\Sth with Py\重要性程度分析\决策树贝叶斯优化结果.txt', 'w') as f:
    for key, value in best_params.items():
        f.write(f'{key}: {value}\n')
    f.write(f'Best Score: {best_score}\n')

'''贝叶斯梯度提升树寻优'''


# 定义目标函数和参数空间
def optuna_objective(trial):
    # 定义参数空间
    max_depth = trial.suggest_int('max_depth', 3, 10)
    learning_rate = trial.suggest_float('learning_rate', 0.001, 0.1, log=True)
    n_estimators = trial.suggest_int('n_estimators', 50, 200)
    subsample = trial.suggest_float('subsample', 0.5, 1.0)

    # 定义评估器
    gbr = GradientBoostingRegressor(
        max_depth=max_depth,
        learning_rate=learning_rate,
        n_estimators=n_estimators,
        subsample=subsample,
        random_state=1412, )

    # 定义交叉过程,输出负均方误差
    cv = KFold(n_splits=5, shuffle=True, random_state=1412)
    validation_loss = cross_validate(gbr, X, y,
                                     scoring='neg_mean_squared_error',
                                     cv=cv,
                                     verbose=True,
                                     n_jobs=-1,
                                     error_score='raise')
    return np.mean(validation_loss['test_score'])


# 定义优化目标函数
def optimizer_optuna(n_trials):
    study = optuna.create_study(sampler=optuna.samplers.TPESampler(n_startup_trials=20, n_ei_candidates=30),
                                direction='maximize')
    study.optimize(optuna_objective, n_trials=n_trials, show_progress_bar=True)

    print('梯度提升树最优参数:\nbest_params:', study.best_trial.params,
          '梯度提升树最优得分:\nbest_score:', study.best_trial.value, '\n')

    return study.best_trial.params, study.best_trial.value

import warnings

warnings.filterwarnings('ignore', message='The objective has been evaluated at this point before trails')
optuna.logging.set_verbosity(optuna.logging.ERROR)
best_params, best_score = optimizer_optuna(100)

# 保存最优参数和最优得分到文件
with open(r'D:\2暂存文件\Sth with Py\重要性程度分析\梯度提升树贝叶斯优化结果.txt', 'w') as f:
    for key, value in best_params.items():
        f.write(f'{key}: {value}\n')
    f.write(f'Best Score: {best_score}\n')

# 结束计时
end_time = time.time()

# 输出执行时间
execution_time = end_time - start_time
print("模型训练执行时间: {:.2f}秒".format(execution_time))

决策树模型最优参数及最佳得分如下:

max_depth: 11、min_samples_split: 18、min_samples_leaf: 13、max_features: 12
Best Score: -0.24607607821335736

随机森林模型最优参数及最佳得分如下:

n_estimators: 30、max_depth: 19、max_features: 24
Best Score: -0.18016603147647478

梯度提升树模型最优参数及最佳得分如下:

max_depth: 9、learning_rate: 0.0418665547136736、n_estimators: 188、subsample: 0.676537978032126
Best Score: -0.16401985559476492


树模型

        树模型,例如决策树和随机森林,能够通过对数据的划分建立一棵树形结构。它可以考虑不仅是线性关系,还包括非线性和交互作用。树模型不仅能够判断特征的重要性,还能够提供每个特征对目标变量的具体影响程度。通过这种方式,我们可以更好地理解和解释特征的重要性。另外,树模型还能够处理缺失值和离群点,使得分析结果更加鲁棒。此外,树模型还可以处理各种类型的特征,包括连续型、分类型以及文本型特征,具有很强的适应性。

        其中源码和绘图结果如下:

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor
import matplotlib.pyplot as plt
import time
plt.rcParams['font.sans-serif']=['SimHei'] # 把中文字体改成国际黑体
plt.rcParams['axes.unicode_minus'] = False # 显示负号
start_time = time.time()

# 读取数据
data = pd.read_csv(r'D:\2暂存文件\Sth with Py\重要性程度分析\data.csv')
X = data.iloc[0:5000,[0, 1, 2, 3, 4, 5, 6, 7]]
y = data.iloc[0:5000,8]


'''决策树'''
model_dtr = DecisionTreeRegressor(max_depth=11,
                                  min_samples_split=18,
                                  min_samples_leaf=13,
                                  max_features=12)
model_dtr.fit(X, y)
importances_dtr = model_dtr.feature_importances_

'''随机森林'''
model_rfr = RandomForestRegressor(n_estimators=30,max_depth=19,max_features=24)
model_rfr.fit(X, y)
importances_rfr = model_rfr.feature_importances_

'''梯度提升树'''
model_gbr = GradientBoostingRegressor(max_depth=9,learning_rate=0.0418665547136736,n_estimators=188,subsample=0.676537978032126)
model_gbr.fit(X, y)
importances_gbr = model_gbr.feature_importances_

# 创建特征名称列表
feature_names = ['MedInc','HouseAge','AveRooms','AveBedrms','Population','AveOccup','Latitude','Longitude']

# 将特征名称和重要性值进行配对
feature_importances_dtr = list(zip(feature_names, importances_dtr))
print('决策树特征重要性:',feature_importances_dtr)
feature_importances_rfr = list(zip(feature_names, importances_rfr))
print('\n随机森林特征重要性:',feature_importances_rfr)
feature_importances_gbr = list(zip(feature_names, importances_gbr))
print('\n梯度提升树特征重要性:',feature_importances_gbr)

'''绘图'''
tree = pd.read_excel(r'D:\2暂存文件\Sth with Py\重要性程度分析\树模型重要性.xlsx')
labels=["特征","Decision trees","Random Forest","GBDT","Average"]

# 把dataframe转换为list
x = tree['特征'].values.tolist()
y1 = tree['Decision trees'].values.tolist()
y2 = tree['Random Forest'].values.tolist()
y3 = tree['GBDT'].values.tolist()
y4 = tree['Average'].values.tolist()

plt.bar(x=np.arange(len(x))-0.2,height=y1,label="Decision trees",color="#AADCE0",width=0.1)
plt.bar(x=np.arange(len(x))-0.1,height=y2,label="Random Forest",color="#FFD06F",width=0.1)
plt.bar(x=x,height=y3,label="GBDT",color="#FFE6B7",width=0.1)
plt.bar(x=np.arange(len(x))+0.1,height=y4,label="Average",color="#E76254",width=0.1)

plt.legend(loc="upper right")
plt.xticks(x)
轴=plt.gca()
轴.set_xticklabels(x,rotation=45,ha="center")
图形=plt.gcf()
plt.xlabel('Feature',fontsize=15)
plt.ylabel('Importance',fontsize=15)
plt.title('Feature Importance',fontsize=18)
图形.subplots_adjust(left=0.1,bottom=0.3)
plt.savefig(r'D:\2暂存文件\Sth with Py\重要性程度分析\树模型重要性.png',dpi=600)
# 输出执行时间
end_time = time.time()
execution_time = end_time - start_time
print("模型训练执行时间: {:.2f}秒".format(execution_time))
plt.show()
树模型重要性分析图

SHAP值法

        SHAP值法采用了一种更为细致的方法来解释特征重要性。它通过计算每个特征对模型预测结果的贡献程度,从而揭示出特征之间的相互作用和非线性关系。这使得我们能够更全面地了解特征对目标的影响,而不仅仅局限于线性关系的分析。本文使用随机森林回归模型,其中数据使用归一化后的数据。代码和摘要图、特征重要性图如下:

import pandas as pd
import shap
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestRegressor
import matplotlib.pyplot as plt
import time
plt.rcParams['font.sans-serif']=['SimHei'] # 把中文字体改成国际黑体
plt.rcParams['axes.unicode_minus'] = False # 显示负号

# 读取数据
normalized_data = pd.read_excel(r'D:\2暂存文件\Sth with Py\重要性程度分析\归一化数据.xlsx')
X = normalized_data.iloc[:,[0, 1, 2, 3, 4, 5, 6, 7]]
y = normalized_data.iloc[:,8]

start_time = time.time()

# 初始化随机森林模型
model = RandomForestRegressor(n_estimators=30,max_depth=19,max_features=24)

# 训练模型
model.fit(X, y)

# 创建一个Explainer对象
explainer = shap.Explainer(model)

# 计算SHAP值
shap_values = explainer.shap_values(X)

# 结束计时
end_time = time.time()

# 输出执行时间
execution_time = end_time - start_time
print("模型训练执行时间: {:.2f}秒".format(execution_time))

# 打印特征重要性得分
shap.summary_plot(shap_values, X)

# 打印每个特征的重要性图
shap.summary_plot(shap_values, X, plot_type="bar")
SHAP值摘要图
SHAP值特征重要性图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/940940.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微前端:重塑大型项目的前沿技术

引言 随着互联网技术的飞速发展,前端开发已经从简单的页面制作逐渐转变为复杂的应用开发。在这个过程中,传统的前端开发模式已经难以满足大型项目的需求。微前端作为一种新的前端架构模式,应运而生,它旨在解决大型项目中的前端开…

C语言基础语法——数据类型

数据类型介绍 数据类型:数据所属的类型 数据类型的作用:编译器预算数据分配的内存空间大小 变量 变量的语法 在计算机程序中,变量是用来存储数据的一个内存区域,并用一个名字来表示这个区域。 在程序运行过程中&#xff0…

Android事件分发

Android事件分发是指触摸屏幕的事件分发,在手指触摸屏幕后所产生的一系列事件中,典型的事件类型有如下几种: MotionEvent.ACTION_DOWN ——手指刚接触屏幕MotionEvent.ACTION_MOVE——手指在屏幕上面滑动MotionEvent.ACTION_UP——手指从屏幕上松开的一…

C语言每日一题 ----计算日期到天数转换(Day 2)

本专栏为c语言练习专栏,适合刚刚学完c语言的初学者。本专栏每天会不定时更新,通过每天练习,进一步对c语言的重难点知识进行更深入的学习。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C语言天天练 &#x…

m3u8 blob视频免费下载

F12点开找到这个视频url最后是.m3u8结尾 http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html 在上边的网址转Mp4下载即可

HBase集群环境搭建与测试

🥇🥇【大数据学习记录篇】-持续更新中~🥇🥇 个人主页:beixi 本文章收录于专栏(点击传送):【大数据学习】 💓💓持续更新中,感谢各位前辈朋友们支持…

【第四阶段】kotlin语言的List创建与元素获取

1.list创建 val list listOf("jave","kotlin","c","c")2.list集合获取的三种方式 开发过程中尽量使用getOrElse()或者getOrNull,因为他可以防止崩溃取值 package Stage4fun main() {//list 创建val list listOf("jav…

m4s格式转换mp4

先安装 ffmpeg,具体从官网可以查到,https://ffmpeg.org,按流程走。 转换代码如下,可以任意选择格式导出 import subprocess import osdef merge_audio_video(input_audio_path, input_video_path, output_mp4_path):# 构建 FFmpe…

ViT论文Pytorch代码解读

ViT论文代码实现 论文地址:https://arxiv.org/abs/2010.11929 Pytorch代码地址:https://github.com/lucidrains/vit-pytorch ViT结构图 调用代码 import torch from vit_pytorch import ViTdef test():v ViT(image_size 256, patch_size 32, num_cl…

【第四阶段】kotlin语言可变list集合

1.可变list集合 完整写法 var list:MutableList<String> mutableListOf<String>("java","kotlin","c","c") 省略写法 var list mutableListOf("java","kotlin","c","c")fun ma…

CobaltStrike提权

攻击机&#xff1a;Kali Linux 靶 机&#xff1a;Windows 7 一、上线CS 复制命令&#xff0c;在靶机执行上线CS 2.安装插件&#xff0c;获取shell https://github.com/rsmudge/ElevateKit 上线CS 右击shell&#xff0c;选择插件 有七个模块可以利用&#xff0c;可以逐一…

C++实现YOLOP

C实现YOLOP 一、简介 使用OpenCV部署全景驾驶感知网络YOLOP&#xff0c;可同时处理交通目标检测、可驾驶区域分割、车道线检测&#xff0c;三项视觉感知任务&#xff0c;依然是包含C和Python两种版本的程序实现 onnx文件从百度云盘下载&#xff0c;链接&#xff1a;https://…

【AutoLayout案例07-如何通过代码添加约束 Objective-C语言】

一、那么,接下来,我们就给大家介绍一下,如何通过代码,来实现这个AutoLayout 1.咱们之前是不是都是通过,storyboard、来拖、拉、拽、的方式实现的吧 现在给大家介绍一下,如何通过代码,来实现 在继续介绍,如何通过代码,来实现AutoLayout之前呢, 我们先要给大家补充一…

基于Java+SpringBoot+Vue前后端分离疫苗发布和接种预约系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

前端开发之Element Plus的分页组件el-pagination显示英文转变为中文

前言 在使用element的时候分页提示语句是中文的到了element-plus中式英文的&#xff0c;本文讲解的就是怎样将英文转变为中文 效果图 解决方案 如果你的element-plus版本为2.2.29以下的 import { createApp } from vue import App from ./App.vue import ElementPlus from …

ruoyi-vue-plus 配置邮箱

ruoyi-vue-plus 配置邮箱 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对你有帮助请…

Java实现根据短连接获取1688商品详情数据,1688淘口令接口,1688API接口封装方法

要通过1688的API获取商品详情数据&#xff0c;您可以使用1688开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过1688开放平台API获取商品详情属性数据接口&#xff1a; 首先&#xff0c;确保您已注册成为1688开放平台的开发者&#xf…

网络工程师的尽头是……

大家好&#xff0c;我是许公子。 最近工作挺忙&#xff0c;很久没有给你们输出文章了&#xff0c;抽空和大家唠嗑唠嗑。 前两天&#xff0c;一个实习生问了我这个问题&#xff1a; “网络工程师的尽头是什么&#xff1f;” 我当时一下子&#xff0c;脑子空白了&#xff0c;…

stackoverflow问题

Stack Overflow requires external JavaScript from another domain, which is blocked or failed to load. stackoverflow引用了谷歌中被屏ajax.googleapis.com的jquery.min.js文件。“https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js” 方案1.打开网站…

Viobot算法控制

一.上位机控制 状态反馈在系统反馈出会根据当前系统状态显示。 控制是在操作栏里面的一个选项三个按键。具体的已经在前面一篇基本功能使用及介绍中讲过了。 二.ROS控制 算法的控制我们也整合成了一个ROS msg&#xff0c;具体的msg信息可以查看demo里面的msg包的algo_ctrl.m…