当前位置:首页>python>期刊图片复现|Python绘制机器学习模型特征重要性及其对预测结果影响方向的环形SHAP组合图

期刊图片复现|Python绘制机器学习模型特征重要性及其对预测结果影响方向的环形SHAP组合图

  • 2026-10-11 08:20:53
期刊图片复现|Python绘制机器学习模型特征重要性及其对预测结果影响方向的环形SHAP组合图

代码绘制成果展示

论文:Environmental gradients explain nearshore microplastic distribution patterns: insights from machine learning models
论文原图
机器学习模型特征重要性及其对预测结果影响方向的环形SHAP组合图,左上角标号表明为子图编号。图中心标注的文本说明当前解释的是什么模型,同时表明是保留了95%置信区间内的样本分布。图最外围一圈标注了特征变量名称;左上方的径向刻度尺用于量化SHAP值的范围,图中加粗黑色实线圆对应着SHAP=0的基准分界线。特征名称对应的每一列散点代表了数据集中具体样本的SHAP值分布情况,底部图例表明了不同颜色的点代表的含义,散点的聚集宽度直观反映了数值的集中密度。三条闭合的多边形折线分别表示了各个特征正向SHAP均值,负向SHAP均值的,SHAP绝对值全局平均值。
注意:此为我个人理解,做法可能与原文存在出入,使用前请阅读原文
仿图
多种配色

代码解释

第一部分

库的导入以及字体设置
# =========================================================================================# ====================================== 1. 环境设置 =======================================# =========================================================================================import osimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.model_selection import train_test_split, GridSearchCV

第二部分

颜色库
# =========================================================================================# ======================================2.颜色库=======================================# =========================================================================================COLOR_SCHEMES = {    1: ('#B63232', '#2A72B5', '#E88B46'),}

第三部分

单个模型环形SHAP图绘制函数:参数初始化与均值计算,均匀分配角度,计算每个特征的全局SHAP绝对值均值(用于衡量总体特征重要性),所有大于0的SHAP值的均值,所有小于等于0的SHAP值的均值。
# =========================================================================================# ======================================3.单个模型环形SHAP图绘制函数=======================================# =========================================================================================def draw_model_circular_shap(ax, model_name, shap_vals, feature_names, color_pos, color_neg, color_mean, letter):    n_features = len(feature_names) #输入特征总数量    angles = np.linspace(0, 2 * np.pi, n_features, endpoint=False) #生成等间距的极坐标角度    angles_closed = np.append(angles, angles[0]) #将第一个角度值添加到数组末尾,闭合    mean_abs_shap = np.mean(np.abs(shap_vals), axis=0) #计算各特征在所有样本上的SHAP值绝对值的平均值    mean_pos_shap = np.zeros(n_features) #各特征正向SHAP均值    mean_neg_shap = np.zeros(n_features) #各特征负向SHAP均值        mean_pos_shap[i] = np.mean(pos_vals) if len(pos_vals) > 0 else 0        mean_neg_shap[i] = np.mean(neg_vals) if len(neg_vals) > 0 else 0    #将均值数组闭合,首尾相接    mean_abs_shap_closed = np.append(mean_abs_shap, mean_abs_shap[0])    mean_pos_shap_closed = np.append(mean_pos_shap, mean_pos_shap[0])    mean_neg_shap_closed = np.append(mean_neg_shap, mean_neg_shap[0])

第四部分

单个模型环形SHAP图绘制函数:范围设定与坐标轴清理
    real_min_val = np.min(shap_vals) #SHAP值全局最小值    real_max_val = np.max(shap_vals) #SHAP值全局最大值    val_span = real_max_val - real_min_val #计算极差    ax.set_theta_offset(np.pi / 2) #起始角度    ax.set_theta_direction(-1) #顺时针    ax.set_ylim(r_min, r_outer) #径向范围    ax.grid(False) #去掉默认网格线    ax.spines['polar'].set_visible(False) #去掉边框    ax.set_yticks([]) #去掉径向刻度标签

第五部分

单个模型环形SHAP图绘制函数:绘制参考线(背景的虚线圆圈,实线径向线,shap=0的圆圈)与边界(中心白色圆的外圈)
    theta_full = np.linspace(0, 2 * np.pi, 300) #生成均匀角度用于绘制平滑的参考圆圈    grid_radii = np.linspace(r_inner, real_max_val + val_span * 0.05, 5) #背景虚线圈半径    #遍历半径    for r in grid_radii:        #绘制背景虚线圈        ax.plot(theta_full, #角度                np.full_like(theta_full, r), #半径                color='gray', #颜色                linestyle='--', # 设置线条样式为虚线                linewidth=1, # 设置线条宽度为0.8                alpha=0.5, # 设置透明度为0.5(半透明)                zorder=1) # 设置绘图层级置底    #中心圆的外框    ax.plot(theta_full,  #角度            np.full_like(theta_full, r_inner), #半径            color='black', #颜色            linestyle='-', #样式            linewidth=1.5, #线宽            zorder=2) #层    #SHAP=0的分界圆    ax.plot(theta_full, #角度            np.full_like(theta_full, 0), #半径            color='#404040', #颜色            linestyle='-', #样式            linewidth=2.5, #线宽            zorder=2) #层

第六部分

单个模型环形SHAP图绘制函数:绘制带抖动的散点图,绘制时剔除掉前后2.5%的极端SHAP值。 把极径范围切分成多个箱子,统计每个箱子内有多少个数据点。然后将落入同一个箱子里的数据点依次安排在不同的角度轨道上。优先排列在特征的中心基准线上,随后左右交替扩散。 最后,将过滤及加入角度抖动后的点,按照SHAP值正负分别绘制成不同颜色的半透明散点。
    #遍历特征绘制散点图    for i inrange(n_features):        angle = angles[i] #角度        vals = shap_vals[:, i] #获取该特征的所有样本SHAP值        low_bound, high_bound = np.percentile(vals, [2.5, 97.5]) #计算95%置信区间的上下限        mask_95 = (vals >= low_bound) & (vals <= high_bound) #剔除前2.5%和后2.5%的极端异常值        vals_filtered = vals[mask_95] #剔除后数据        #绘制正SHAP值        ax.scatter(angle + jitter_vals_filtered[pos_mask], #角度+偏移                   vals_filtered[pos_mask], #半径                   color=color_pos, #填充颜色                   s=18, #大小                   alpha=0.65, #透明度                   zorder=3, #层                   edgecolors='none') #不绘制边        #绘制负SHAP值        ax.scatter(angle + jitter_vals_filtered[neg_mask], #角度+偏移                   vals_filtered[neg_mask],  #半径                   color=color_neg, #填充颜色                   s=18, #大小                   alpha=0.65, #透明度                   zorder=3, #图                   edgecolors='none')  #不绘制边

第七部分

单个模型环形SHAP图绘制函数:绘制均值闭合线
   #SHAP绝对值均值闭合线    ax.plot(angles_closed, #角度            mean_abs_shap_closed, #半径            color=color_mean, #颜色            linewidth=2, #线            zorder=5) #层    #均值曲线上对应特征的角点标记    ax.scatter(angles, #角度               mean_abs_shap, #半径               color=color_mean, #颜色               s=10, #大小               zorder=5) #层    #SHAP正向均值的闭合线    ax.plot(angles_closed, #角度            mean_pos_shap_closed, #半径            color=color_pos, #颜色            linewidth=1.0, #线宽            zorder=5) #层    #SHAP负向均值的闭合线    ax.plot(angles_closed,#角度            mean_neg_shap_closed, #半径            color=color_neg, #颜色            linewidth=1.0, #线宽            zorder=4) #层

第八部分

单个模型环形SHAP图绘制函数:绘制刻度线,中心文本,子图编号
    axis_angle = np.deg2rad(-20) #用于绘制数值刻度轴的角度    #数值刻度轴    ax.plot([axis_angle, axis_angle], #角度            [r_inner, real_max_val + val_span * 0.05], #半径范围            color='black', #颜色            linewidth=1.0, #线宽            zorder=5) #层    all_ticks = np.linspace(real_min_val, real_max_val, 7) #生成均匀分布的刻度点    d_theta = 0.04 #刻度线长    ax.text(0, #x            r_min, #y            f"{model_name}\n95% CI", #文本            ha='center', #水平            va='center', #垂直            fontsize=14, #字体大小            fontweight='bold', #加粗            zorder=6) #层    #子图编号    ax.text(-0.05, #x            1.15, #Y            letter, #编号            transform=ax.transAxes, #坐标系            fontsize=32, #大小            fontweight='bold', #加粗            va='top', #垂直定            ha='right') #水平

第九部分

主绘图函数:绘制子图和组合图,并分别进行保存
# =========================================================================================# ======================================4.主绘图函数=======================================# =========================================================================================def plot_circular_shap_charts(shap_data_dict, top_features_dict, scheme_id=1):    fig, axes = plt.subplots(1, #行                             3, #列                             figsize=(25, 8), #尺寸                             subplot_kw=dict(polar=True)) #极坐标        #调用绘图函数绘制组合图        draw_model_circular_shap(axes[idx], #画布                                 model_name, #模型                                 top_shap_vals, #SHAP                                 top_features, #特征                                 color_pos, #正颜色                                 color_neg, #负颜色                                 color_mean, #均值颜色                                 letters[idx]) #子图编号        #创建子图画布        fig_single, ax_single = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))        #绘制子图        draw_model_circular_shap(ax_single, model_name, top_shap_vals, top_features,color_pos, color_neg, color_mean, letters[idx])        # 创建用于独立图表图例说明的定制线条对象(此处为空线条)        mean_line_s = mlines.Line2D([], #占位                                    [],#占位                                    color=color_mean, #颜色                                    marker='o', #圆形                                    markersize=20, #大小                                    label='SHAP mean', #图例文本                                    linestyle='None') #不绘制线        # 创建用于独立图表正向值的图例空对象        pos_dot_s = mlines.Line2D([], #占位                                  [],#占位                                  color=color_pos, #颜色                                  marker='o', #圆形                                  markersize=20, #大小                                  label='SHAP positive', #图例文本                                  linestyle='None') #不绘制线        single_save_dir = os.path.join(base_path, model_name)        os.makedirs(single_save_dir, exist_ok=True)        #保存        fig_single.savefig(os.path.join(single_save_dir, f'shap_circular_{model_name}_scheme_{scheme_id}.png'), dpi=300,bbox_inches='tight')        fig_single.savefig(os.path.join(single_save_dir, f'shap_circular_{model_name}_scheme_{scheme_id}.pdf'),bbox_inches='tight')        plt.close(fig_single) #关闭    #创建组合图图例    #均值    mean_line = mlines.Line2D([], #占位                              [],#占位                              color=color_mean, #颜色                              marker='o', #圆形                              markersize=26, # 大小                              label='SHAP mean', #文本

第十部分

执行部分:读取了主数据集和独立验证集,拆分成特征X和目标y,主数据集划分为训练和测试集。定义了RF、XGB、CatBoost等模型的参数字典。通过交叉验证网格搜索寻找三个模型各自的最优超参数组合,并将最优模型存入字典中。遍历模型,在独立验证集上解析模型特征贡献度。由于这是多分类问题,代码首先将所有分类的SHAP绝对值求均值来衡量特征的总体实力,从大到小对特征进行排序,筛选出排名前12的特征。最后,取出目标类别的SHAP值保留后续画图。执行可视化绘制出图。
# =========================================================================================# ======================================5.执行部分=======================================# =========================================================================================if __name__ == '__main__':    excel_filename = r'\simulated_microplastic_data.xlsx'  #模型数据集    df_main = pd.read_excel(excel_filename)  #读取    feature_names = df_main.drop(columns=['Target_Class']).columns.tolist()  #特征名    X_main = df_main.drop(columns=['Target_Class']).values  #特征数据    y_main = df_main['Target_Class'].values  #目标数据    #划分训练集与测试集    best_models = {}  #存放最佳模型    model_names = ['Random Forest', 'XGBoost', 'CatBoost']  #模型名称    #超参数网格    rf_param = {'n_estimators': [50, 100],                'max_depth': [5, 10, None]}    #配置网格搜索    rf_grid = GridSearchCV(RandomForestClassifier(random_state=42, class_weight='balanced'), rf_param, cv=3, n_jobs=-1)    rf_grid.fit(X_train, y_train)  #拟合    best_models['Random Forest'] = rf_grid.best_estimator_  #最佳RF模型    #超参数网格    xgb_param = {'n_estimators': [50, 100],                 'max_depth': [3, 5],                 'learning_rate': [0.1, 0.2]}    #配置网格搜索    xgb_grid = GridSearchCV(XGBClassifier(random_state=42, eval_metric='mlogloss'), xgb_param, cv=3, n_jobs=-1)    xgb_grid.fit(X_train, y_train)  #拟合    best_models['XGBoost'] = xgb_grid.best_estimator_  #最佳XGBoost模型    #超参数网格    cb_param = {'iterations': [50, 100],                'depth': [4, 6],                'learning_rate': [0.1]}    #配置网格搜索    cb_grid = GridSearchCV(CatBoostClassifier(random_state=42, verbose=0, auto_class_weights='Balanced'), cb_param,                           cv=3, n_jobs=-1)    cb_grid.fit(X_train, y_train)  #拟合    best_models['CatBoost'] = cb_grid.best_estimator_  #最佳CatBoost模型    shap_data_dict = {}  #存放SHAP结果    top_features_dict = {}  #按各模型存放筛选后头部特征    k_features = 12  #要呈现的上限,top    plot_all = True    if plot_all:        for i in COLOR_SCHEMES.keys():            plot_circular_shap_charts(shap_data_dict, top_features_dict, scheme_id=i)    else:        target_scheme = 1        plot_circular_shap_charts(shap_data_dict, top_features_dict, scheme_id=target_scheme)

如何应用到你自己的数据

1.设置是一次绘制一张图还是一次性绘制出所有配色的图,执行部分:

plot_all = True

2.设置模型数据集路径,执行部分:

excel_filename = r'data.xlsx'  #模型数据集

3.设置独立验证数据集路径,执行部分:

ind_excel_filename = r'independent_validation_data.xlsx'

4.设置目标数据,执行部分:

y_main = df_main['Target_Class'].values  #目标数据

5.设置特征数据,执行部分:

X_main = df_main.drop(columns=['Target_Class']).values  #特征数据

6.设置超参数网格,执行部分:

rf_param = {'n_estimators': [50, 100],            'max_depth': [5, 10, None]}

7.设置要绘制的特征,执行部分:

k_features = 12  #要呈现的上限,top

8.设置保存路径,主绘图函数部分:

base_path = r''

推荐

期刊图片复现|Python绘制二维偏依赖PDP图
期刊复现|python绘制基于SHAP分析和GAM模型拟合的单特征依赖图
期刊复现|用Python绘制SHAP特征重要性总览图、依赖图、双特征交互效应SHAP图,解锁XGBoost模型的终极奥秘
期刊图片复现|Python绘制shap重要性蜂巢图+单特征依赖图+交互效应强度气泡图+交互效应依赖图(回归+二分类+分类)

获取方式

公众号中的所有所有的免费代码都已经下架了,都并入到付费部分里了,付费合集代码和数据的购买通道已经开通,全部合集100元,后续将会持续更新,决定购买请后台私信我,注意只会分享练习数据和代码文件,不会提供答疑服务,代码文件中已经包含了每行代码的完整注释,购买前请确保真的需要!!!

最新文章

随机文章