
代码绘制成果展示









代码解释


第一部分

# =========================================================================================# ====================================== 1. 环境设置 =======================================# =========================================================================================import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom matplotlib.patches import FancyBboxPatch, Patchfrom matplotlib.colors import LinearSegmentedColormap, Normalizefrom sklearn.model_selection import train_test_split, GridSearchCV

第二部分

# =========================================================================================# ======================================2.颜色库============================================# =========================================================================================COLOR_SCHEMES = {1: {'cmap': ['#4f4f8c', '#ffffff', '#a83232'], 'roc': ['#E53935', '#43A047', '#1E88E5', '#8E24AA'],'table_header': '#878ca8','table_rows': [('#e4f0f0', '#8bb9c0'), ('#ffeaeb', '#f89e9d'), ('#fff9e5', '#f5d676'), ('#e9f4e6', '#aed4a4'),('#eef0f3', '#b5bdcb')]},}SCHEME_ID = 1 # 设置当前使用的配色方案global_scheme = COLOR_SCHEMES[SCHEME_ID] # 获取对应的配色方案

第三部分

# =========================================================================================# ======================================3.蜂巢图抖动计算函数===================================# =========================================================================================def simple_beeswarm(x_values, nbins=40, width=0.1):hist_range = (np.min(x_values), np.max(x_values)) # 数据的最小值和最大值范围if hist_range[0] == hist_range[1]: # 如果最大值等于最小值bin_indices = np.clip(bin_indices, 0, nbins - 1) # 索引范围y_values = np.zeros_like(x_values) # 初始化Y轴抖动值max_count = counts.max() # 获取直方图中的最大计数值current_width = (counts[i] / max_count) * width # 根据当前箱子的密度计算抖动宽度return y_values # 返回计算好的Y轴抖动坐标

第四部分


# =========================================================================================# ======================================4.ROC 曲线==========================================# =========================================================================================def plot_single_roc(tprs, aucs, title_text, letter):# 创建画布fig, ax = plt.subplots(figsize=(6.5, 5.5))custom_legend_handles = [] # 用于存储自定义图例句柄roc_colors = global_scheme['roc'] # 获取颜色ax.set_xlabel('False positive rate', fontsize=16, fontweight='bold') # x轴标题ax.set_ylabel('True positive rate', fontsize=16, fontweight='bold') # y轴标题# 设置主刻度线ax.tick_params(axis='both', which='major', length=6, width=2, labelsize=14)# 设置x、y轴数值标注粗细for label in ax.get_xticklabels() + ax.get_yticklabels():label.set_fontweight('bold')box_y0 = 1.08 # 顶部标题背景框的起始Y坐标box_height = 0.12 # 顶部标题背景框的高度# 创建圆角矩形背景框对象box = FancyBboxPatch((0, box_y0), # 起始位置1.0, # 背景框宽度box_height, # 高度boxstyle="round,pad=0.0,rounding_size=0.04", # 样式ec="#d0d0d0", # 边框颜色fc="white", # 填充颜色lw=3.0, # 边框线宽transform=ax.transAxes, # 坐标轴clip_on=False) # 允许在坐标轴之外绘制ax.add_patch(box) # 将背景框添加到图形中# 遍历边框for spine in ax.spines.values():spine.set_linewidth(2) # 线宽

第五部分


# =========================================================================================# ======================================5.混淆矩阵绘制函数==========================================# =========================================================================================def plot_custom_confusion_matrix(cm, letter, is_train=True):# 创建画布和坐标轴fig, ax = plt.subplots(figsize=(6.5, 5.5))ax.tick_params(top=False, bottom=False, left=False, right=False)ax.set_xticks(range(4)) # 设置x轴的刻度位置ax.set_yticks(range(4)) # 设置y轴的刻度位置labels = ['F1', 'F2', 'F3', 'F4'] #类别sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) # 创建用于颜色条对象sm.set_array([]) # 初始化空数组,以便生成颜色条# 添加颜色条cbar = fig.colorbar(sm, ax=ax, fraction=0.046, pad=0.04)cbar.outline.set_visible(False) # 隐藏颜色条外边框cbar.ax.tick_params(size=0, labelsize=14, pad=8) # 隐藏颜色条的刻度线# 为颜色条创建一个圆角裁剪框clip_box = FancyBboxPatch((0, 0),1.0, # 裁剪框的宽度比例1.0, # 裁剪框的高度比例boxstyle="round,pad=0.0,rounding_size=0.5", # 圆角样式mutation_aspect=0.06, # 控制圆角在宽高比下的变形程度transform=cbar.ax.transAxes, # 基于颜色条轴坐标进行变换ec="#d0d0d0", # 边界颜色fc="none", # 无填充lw=2.5, # 裁剪框线宽clip_on=False) # 允许超越边界绘制cbar.ax.add_patch(clip_box) # 将圆角裁剪框加入到颜色条轴上

第六部分


# =========================================================================================# ======================================6.绘制性能指标可视化表格=========================================# =========================================================================================def plot_metrics_table(train_vals, test_vals, letter):# 创建画布fig, ax = plt.subplots(figsize=(8, 4.2))ax.set_xlim(0, 10) # x轴范围ax.set_ylim(-0.2, 6.2) # y轴范围ax.add_patch(FancyBboxPatch((0.2, 5.1), # 起始位置9.6, # 宽度0.9, # 高度boxstyle="round,pad=0,rounding_size=0.45", # 样式fc=bg_header, # 填充色ec='none')) # 隐藏边缘线# 添加表头文本ax.text(2.0, 5.55, letter, fontsize=18, fontweight='bold', color='white', va='center', ha='center')ax.text(5.25, 5.55, 'Training', fontsize=18, fontweight='bold', color='white', va='center', ha='center')ax.text(8.35, 5.55, 'Test', fontsize=18, fontweight='bold', color='white', va='center', ha='center')ax.add_patch(FancyBboxPatch((4.0, y_base + 0.1), # 坐标2.5, # 宽度0.7, # 高度boxstyle="round,pad=0,rounding_size=0.35", # 样式fc=dark_c, # 填充色ec='none')) # 无边框线m_tr, s_tr = train_vals[i] # 拆分为均值和标准差# 训练集ax.text(5.25, # xy_base + 0.45, # Yf"{m_tr:.2f} ± {s_tr:.2f}", # 数值fontsize=16, # 大小color='black', # 字体颜色va='center', # 垂直对齐ha='center') # 水平对齐# 添加高亮小框ax.add_patch(FancyBboxPatch((7.1, y_base + 0.1), # 坐标2.5, # 宽0.7, # 高度boxstyle="round,pad=0,rounding_size=0.35", # 样式fc=dark_c, # 填充色ec='none')) # 无边框线

第七部分


# =========================================================================================# ======================================7.SHAP 特征重要性热图=========================================# =========================================================================================def plot_shap_feature_importance(shap_data, features, letter):# 创建画布fig, ax = plt.subplots(figsize=(11, 4))# 配置轴刻度参数ax.tick_params(axis='both', # 两个轴which='both', # 应用于主刻度及副刻度length=0, # 长度top=False, # 关闭顶部刻度线bottom=False, # 关闭底部刻度线left=False, # 关闭左侧刻度线right=False) # 关闭右侧刻度线ax.set_xticks(range(n_features)) # 设置x轴的标签位置ax.xaxis.tick_top() # x轴的特征名称转移到图表正上方显示# 设置x轴顶部的文本ax.set_xticklabels(features, # 特征名rotation=45, # 旋转ha='left', # 水平对齐va='bottom', # 垂直对齐fontsize=14, # 字体大小fontweight='bold') # 加粗clip_box = FancyBboxPatch((0, 0),1.0, # 宽度1.0, # 高度boxstyle="round,pad=0.0,rounding_size=0.5", # 用圆角裁切mutation_aspect=0.08, # 调节长条状态下圆角不变形transform=cbar.ax.transAxes, # 相对坐标系ec="#d0d0d0", # 边框色fc="none", # 内部留白lw=2.5, # 线宽clip_on=False) # 允许跨界

第八部分


# =========================================================================================# ======================================8.SHAP 特征重要性蜂巢图=========================================# =========================================================================================def plot_single_shap_summary(sv, features_data, feature_names, fraction_idx, letter):# 画布fig, ax = plt.subplots(figsize=(7.5, 6))cmap = LinearSegmentedColormap.from_list('custom_cm', global_scheme['cmap'], N=256) # 创建渐变色mean_abs = np.abs(sv).mean(axis=0) # 对每一特征的SHAP值求绝对值后算平均数for label in ax.get_xticklabels():label.set_fontweight('bold')# 设置边框线ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_linewidth(2)# 子图编号ax.text(-0.05, # x1.05, # yletter, # 子图编号transform=ax.transAxes, # 坐标系fontsize=26, # 大小fontweight='bold', # 加粗va='bottom', # 垂直ha='right') # 水平# 图名框属性bbox_props = dict(boxstyle="round,pad=0.4,rounding_size=0.2", # 框体属性ec="#4f4f8c", # 边颜色fc="none", # 填充色lw=2.5, # 边线粗细linestyle="--") # 线条样式# 图名ax.text(0.8, # x0.1, # yf"{class_names[fraction_idx]}", # 内容transform=ax.transAxes, # 坐标系fontsize=16, # 字体大小fontweight='bold', # 加粗ha='center', # 水平va='center', # 垂直bbox=bbox_props) # 应用属性

第九部分


# =================================================================================================# ======================================9.单特征依赖图绘制函数=========================================# =================================================================================================def plot_single_shap_dependence(sv, features_data, feature_names, feature_idx, interaction_idx, fraction_idx, letter):# 创建画布fig, ax = plt.subplots(figsize=(7.5, 6))cmap = LinearSegmentedColormap.from_list('custom_cm', global_scheme['cmap'], N=256) # 自定义线性颜色映射对象# 绘制散点图ax.scatter(x_vals, # Xy_vals, # Yc=color_vals, # 散点的颜色s=25, # 大小alpha=0.8, # 透明度edgecolors='none', # 边缘颜色zorder=2) # 层级# 添加文本ax.text(-0.15, # x1.05, # yletter, # 子图编号transform=ax.transAxes, # 坐标系fontsize=26, # 字体大小fontweight='bold', # 粗细va='bottom', # 垂直ha='right') # 水平clip_box = FancyBboxPatch((0, 0),1.0, # 裁剪框的宽度比例1.0, # 裁剪框的高度比例boxstyle="round,pad=0.0,rounding_size=0.5", # 圆角样式mutation_aspect=0.06, # 控制圆角在宽高比下的变形程度transform=cbar.ax.transAxes, # 基于颜色条轴坐标进行变换ec="#d0d0d0", # 边界颜色fc="none", # 无填充lw=2.5, # 裁剪框线宽clip_on=False) # 允许超越边界绘制cbar.ax.add_patch(clip_box) # 将圆角裁剪框加入到颜色条轴上# 将颜色条实体按照圆角框进行裁剪if hasattr(cbar, 'solids') and cbar.solids is not None:cbar.solids.set_clip_path(clip_box)else:for coll in cbar.ax.collections: # 遍历颜色条轴内的集合coll.set_clip_path(clip_box) # 将集合按照圆角框进行裁剪

第十部分

# =================================================================================================# ======================================11.执行部分=====================================================# =================================================================================================if __name__ == '__main__':df = pd.read_excel(r"data.xlsx") #读取原始数据target_col = 'Label' # 目标变量X = df.drop(columns=[target_col]).values # 特征数据y = df[target_col].values # 提取目标变量数据feature_cols = df.drop(columns=[target_col]).columns.tolist() # 获取特征名称tprs_train = {i: [] for i in range(n_models)} #用于存储各个模型在每一轮训练集上的TPRaucs_train = {i: [] for i in range(n_models)} #用于存储各个模型在每一轮训练集上的AUCtprs_test = {i: [] for i in range(n_models)} #用于存储各个模型在每一轮测试集上的TPRaucs_test = {i: [] for i in range(n_models)} #用于存储各个模型在每一轮测试集上的AUCy_train_bin = label_binarize(y_train, classes=[0, 1, 2, 3]) # 将训练集的原始离散标签二值化为多个 0/1 组成的独热矩阵,为后续绘制各类别的 ROC 曲线做准备y_test_bin = label_binarize(y_test, classes=[0, 1, 2, 3])#实例化模型models_dict = [XGBClassifier(objective='multi:softprob',num_class=n_classes,eval_metric='mlogloss',random_state=iteration, n_jobs=1),RandomForestClassifier(random_state=iteration, n_jobs=1),LGBMClassifier(objective='multiclass',num_class=n_classes,random_state=iteration,n_jobs=1,verbose=-1),CatBoostClassifier(loss_function='MultiClass',classes_count=n_classes,random_seed=iteration,verbose=False,thread_count=1)]print("\n训练完成,开始绘制并保存图像")print("\n开始绘制ROC曲线")plot_single_roc(tprs_train, #TPR数据aucs_train, #AUC数据"Training", #标题"a") #编号plot_single_roc(tprs_test,aucs_test,"Test","b")print("\n开始绘制混淆矩阵和指标图")print("\n正在计算各个模型的 SHAP 特征重要性")shap_data_models = np.zeros((n_models, X.shape[1])) #用于存放模型针对数据每个维度的全局平均特征重要性SHAP值sv_models_dict = {i: {} for i in range(n_models)} #SHAP原始数据feature_names = df.drop(columns=[target_col]).columns.tolist() #提取特征名称print("\n开始绘制SHAP特征重要性热图")#SHAP重要性热图plot_shap_feature_importance(normalized_shap, feature_names, "a")for m_idx in range(n_models):mean_abs_feat = np.abs(sv_models_dict[m_idx][c]).mean(axis=0) #重要性order = np.argsort(mean_abs_feat)[::-1] #排序top1_idx, top2_idx = order[0], order[1] # 两个最重要特征letter_dependence = f"{chr(102 + m_idx)}_Class{c}" #标题# 绘制依赖图plot_single_shap_dependence(sv_models_dict[m_idx][c],#SHAP原始数据X_test_best[m_idx], #特征数据feature_names, #特征名称feature_idx=top1_idx, #主特征interaction_idx=top2_idx, #次特征fraction_idx=m_idx, #模型名letter=letter_dependence) #标题

如何应用到你自己的数据

1.类别数量,第二部分:
n_classes = 4 #类别总数量2.模型数量,第二部分:
n_models = 4 #本次对比的模型数量3.配色方案,第二部分:
SCHEME_ID = 1 # 设置当前使用的配色方案4.设置绘图结果的保存地址,所有绘图函数部分:
plt.savefig(fr"{title_text}_{SCHEME_ID}ROC.png",dpi=300, bbox_inches='tight')5.设置原始数据的路径,执行部分:
df = pd.read_excel(r"data.xlsx") #读取原始数据6.设置目标变量,执行部分:
target_col = 'Label' # 目标变量7.设置迭代次数,执行部分:
n_iterations = 158.设置模型超参数网格,执行部分:
param_grids = { 'XGBoost': {'max_depth': [3, 5], 'learning_rate': [0.05, 0.1], 'n_estimators': [50, 100]}, 'Random Forest': {'max_depth': [3, 5], 'n_estimators': [50, 100]}, 'LightGBM': {'max_depth': [3, 5], 'learning_rate': [0.05, 0.1], 'n_estimators': [50, 100]}, 'CatBoost': {'depth': [3, 5], 'learning_rate': [0.05, 0.1], 'iterations': [50, 100]}}
推荐


获取方式
