置信区间+误差条:机器学习分类评价指标精美呈现

向量数据库大模型机器学习

picture.image

背景

虽然折线图能够直观地展示不同数据集在各个指标上的表现,但它存在一个明显的不足:无法展示指标的 置信区间 和结果的波动范围,这使得无法判断模型评价指标的 稳定性不确定性 ,从而可能掩盖真实的表现差异,如果指标的置信区间较大,单一的得分点并不能充分反映模型的可靠性

picture.image

当将指标的 置信区间误差条 结合,可视化呈现时,不仅能直观地展示模型性能,还能帮助评估结果的可靠性与波动范围

picture.image

代码实现

模型构建


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt 
          
import warnings
          
warnings.filterwarnings("ignore")
          

          
plt.rcParams['font.family'] = 'Times New Roman'
          
plt.rcParams['axes.unicode_minus'] = False
          
# 读取衍生数据集
          
df_derivation_cohort = pd.read_csv("2024-12-19公众号Python机器学习AI_data.csv")
          
# 读取外部验证数据集
          
df_external_validation_cohort = pd.read_csv("2024-12-19公众号Python机器学习AI_val.csv")
          

          
from sklearn.model_selection import train_test_split
          
# 提取目标变量 y,即“Outcome_Occlusion_MI”列
          
y = df_derivation_cohort['Outcome_Occlusion_MI']
          
# 提取特征变量 X,去掉目标变量列
          
X = df_derivation_cohort.drop('Outcome_Occlusion_MI', axis=1)
          

          
# 划分训练集和测试集,20% 为测试集,按 y 的分层抽样
          
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=99)
          

          
# 提取外部验证集的目标变量 y_val
          
y_val = df_external_validation_cohort['Outcome_Occlusion_MI']
          
# 提取外部验证集的特征变量 X_val
          
X_val = df_external_validation_cohort.drop('Outcome_Occlusion_MI', axis=1)
          

          
from sklearn.ensemble import RandomForestClassifier
          
from sklearn.calibration import CalibratedClassifierCV
          

          
# 创建随机森林分类器
          
clf = RandomForestClassifier(
          
    class_weight='balanced_subsample',  # 每个决策树的子样本内,自动调整每个类别的权重,平衡不平衡数据集
          
    criterion='entropy',               # 使用信息增益(熵)作为分裂标准
          
    n_jobs=-1,                         # 使用所有可用的CPU核心加速训练
          
    random_state=42,                   # 固定随机种子,确保结果可复现
          
    max_features='log2',               # 每次分裂时考虑的最大特征数为 log2(总特征数)
          
    n_estimators=20,                   # 随机森林中决策树的数量
          
    min_samples_split=0.01,            # 内部节点分裂所需的最小样本比例(即至少占总样本1%)
          
    min_samples_leaf=0.005,            # 叶子节点所需的最小样本比例(即至少占总样本0.5%)
          
    min_impurity_decrease=1e-2,        # 分裂时要求的最小纯度增益,防止过拟合
          
    bootstrap=True,                    # 使用自助法采样(带放回抽样)构建每棵决策树
          
    ccp_alpha=1e-2,                    # 剪枝时的复杂度参数,增加模型泛化能力
          
    max_samples=0.75,                  # 每棵树只使用75%的样本子集(相对总样本数量)
          
    oob_score=True                     # 使用袋外样本估计模型泛化性能
          
)
          

          
# 对随机森林分类器进行校准
          
clf = CalibratedClassifierCV(
          
    clf,               # 要校准的基础分类器(随机森林)
          
    cv=5,              # 使用5折交叉验证来校准分类器
          
    method="isotonic"  # 使用保序回归法进行概率校准,适合数据较多的情况
          
)
          

          
clf.fit(X_train, y_train)
      

picture.image

通过构建 随机森林分类器 ,对训练集进行拟合、参数优化与 概率校准 ,以提高模型在不平衡数据集上的预测性能,并准备对测试集和外部验证集进行评估

模型评价指标计算


          
from sklearn.metrics import (
          
    confusion_matrix, accuracy_score, precision_score, recall_score, f1_score,
          
    roc_auc_score, cohen_kappa_score
          
)
          

          
from sklearn.utils import resample
          

          
#  clf 是已训练的模型
          
datasets = {
          
    "Training Set": (X_train, y_train),
          
    "Testing Set": (X_test, y_test),
          
    "Validation Set": (X_val, y_val)
          
}
          

          
# 计算训练集、测试集、验证集的指标
          
results_with_ci = {}
          

          
for name, (X, y) in datasets.items():
          
    y_prob = clf.predict_proba(X)[:, 1]  # 预测正类的概率
          
    y_pred = clf.predict(X)             # 预测标签
          
    results_with_ci[name] = calculate_metrics_with_ci(y, y_pred, y_prob)
          

          
# 转换结果为DataFrame
          
results_with_ci_df = pd.DataFrame(results_with_ci).T
          
results_with_ci_df
      

picture.image

这里的 calculate_metrics_with_ci 是一个自定义函数,用于计算分类模型的多项评价指标(如准确率、精确率、召回率、F1分数等),并通过Bootstrap重抽样方法为这些指标估算出置信区间,代码与数据集获取:如需获取本文的源代码和数据集,请添加作者微信联系

折线图可视化


          
# 提取主要指标值 (去掉置信区间,只保留均值)
          
results_clean = results_with_ci_df.applymap(lambda x: float(x.split(' ')[0]))
          

          
# 数据转换为长格式
          
results_long = results_clean.reset_index().melt(id_vars="index", var_name="Dataset", value_name="Score")
          
results_long.rename(columns={"index": "Metrics"}, inplace=True)
          

          
import matplotlib.ticker as ticker
          
# 数据准备: 宽格式 -> 长格式
          
def prepare_data(results_clean):
          
    results_long = results_clean.reset_index().melt(
          
        id_vars="index", 
          
        var_name="Metrics", 
          
        value_name="Score"
          
    )
          
    results_long.rename(columns={"index": "Dataset"}, inplace=True)
          
    return results_long
          

          
# 可视化函数
          
def plot_metrics_long(metrics_long_df, title="Metrics Visualization", save_path=None):
          
    """
          
    绘制折线图: x轴为指标 (Metrics),图例为数据集 (Dataset)。
          
    
          
    Args:
          
        metrics_long_df (DataFrame): 长格式 DataFrame,包含 'Dataset', 'Metrics', 'Score' 三列。
          
        title (str): 图标题。
          
        save_path (str): 可选,若提供路径,则保存图表。
          
    """
          
    # 获取唯一数据集和指标
          
    datasets = metrics_long_df['Dataset'].unique()
          
    metrics = metrics_long_df['Metrics'].unique()
          
    
          
    colors = ['#ff3522', 'brown', 'orange', 'purple', '#0D99D4', '#4fbe5e', 'blue']
          
    plt.figure(figsize=(10, 6), dpi=300)
          
    
          
    # 绘制每个数据集的折线图
          
    for idx, dataset in enumerate(datasets):
          
        subset = metrics_long_df[metrics_long_df['Dataset'] == dataset]
          
        plt.plot(subset['Metrics'], subset['Score'], marker='o', 
          
                 label=dataset, color=colors[idx % len(colors)])
          
    
          
    # 设置坐标轴和样式
          
    ax = plt.gca()
          
    ax.spines['right'].set_visible(False)
          
    ax.spines['top'].set_visible(False)
          
    ax.yaxis.set_major_locator(ticker.MultipleLocator(0.1))
          
    ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.05))
          
    
          
    # 图表属性
          
    plt.title(title, fontsize=12)
          
    plt.xlabel("Metrics", fontsize=10)
          
    plt.ylabel("Score", fontsize=10)
          
    plt.ylim(0.0, 1.1)
          
    plt.xticks(rotation=45, ha='right')
          
    plt.legend(title="Dataset", loc='center left', bbox_to_anchor=(1, 0.5), frameon=False)
          
    plt.grid(which='both', linestyle='--', linewidth=0.5, color='gray')
          

          
    # 保存图表
          
    if save_path:
          
        plt.savefig(save_path, format='pdf', bbox_inches='tight')
          
    plt.tight_layout()
          
    plt.show()
          

          
# 使用 results_clean 进行可视化
          
results_long = prepare_data(results_clean)  # 数据转换
          
plot_metrics_long(results_long, title="Model Performance Across Datasets", save_path="metrics_plot.pdf")
      

picture.image

绘制折线图,其中 X 轴为评价指标(如 Accuracy、Precision 等),不同数据集(如训练集、测试集、验证集)在图例中区分,Y 轴显示各指标的分数

绘制训练集置信区间+误差条可视化


          
import re
          
# 提取 "Training Set" 行数据
          
training_set = results_with_ci_df.loc["Training Set"]
          

          
# 初始化存储列表
          
features = training_set.index.tolist()
          
odds_ratios = []
          
ci_lower = []
          
ci_upper = []
          

          
# 定义提取函数(使用正则表达式)
          
def extract_ci(value):
          
    """提取实际值、置信区间下限和上限"""
          
    match = re.match(r"([\d.]+) \(([\d.]+), ([\d.]+)\)", value)
          
    if match:
          
        return float(match.group(1)), float(match.group(2)), float(match.group(3))
          
    return None, None, None
          

          
# 遍历提取数据
          
for value in training_set:
          
    odds, lower, upper = extract_ci(value)
          
    odds_ratios.append(odds)
          
    ci_lower.append(lower)
          
    ci_upper.append(upper)
          
    
          
# 计算 markersize:值越大,圆圈越小(通过反比例关系)
          
max_size = 300  # 最大圆圈大小
          
min_size = 50   # 最小圆圈大小
          
scaled_markersize = max_size - (odds_ratios / np.max(odds_ratios)) * (max_size - min_size)
          

          
# 绘图
          
fig, ax = plt.subplots(figsize=(8, 6))
          
y_pos = np.arange(len(features))
          

          
# 绘制误差条和动态圆圈
          
for i in range(len(features)):
          
    ax.errorbar(odds_ratios[i], y_pos[i], 
          
                xerr=[[odds_ratios[i] - ci_lower[i]], [ci_upper[i] - odds_ratios[i]]],
          
                fmt='o', color='lightblue', ecolor='lightcoral',
          
                capsize=5, capthick=2, markersize=np.sqrt(scaled_markersize[i]))
          

          
# 设置Y轴
          
ax.set_yticks(y_pos)
          
ax.set_yticklabels(features)
          
ax.invert_yaxis()  # 标签从上到下读取
          
# 设置标题和X轴标签
          
ax.set_xlabel('Evaluation Metrics (95% CI)')
          
ax.set_title('Model Evaluation Metrics: Random Forest')
          
plt.axvline(x=1, linestyle='--', color='grey', linewidth=1)
          
plt.tight_layout()
          
plt.savefig('Model Evaluation Metrics Random Forest.pdf', format='pdf', bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

提取模型评价指标及其置信区间,并通过误差条和动态圆圈大小直观展示随机森林模型的性能表现。 动态圆圈规则 是根据指标值的大小反比例映射到圆圈的尺寸,即 指标值越大,圆圈越小 ,从而通过圆圈的视觉效果突出显示指标的相对表现或重要性。此外,这里的指标(如准确率、精确率、召回率等) 越接近1,表示模型性能越好

绘制所有数据集置信区间+误差条可视化


          
# 定义提取函数(使用正则表达式)
          
def extract_ci(value):
          
    """提取实际值、置信区间下限和上限"""
          
    match = re.match(r"([\d.]+) \(([\d.]+), ([\d.]+)\)", value)
          
    if match:
          
        return float(match.group(1)), float(match.group(2)), float(match.group(3))
          
    return None, None, None
          

          
# 提取每个数据集的指标
          
datasets = ["Training Set", "Validation Set", "Testing Set"]
          
colors = ["lightblue", "lightgreen", "lightcoral"]  # 不同数据集的颜色
          
markers = ["o", "s", "D"]  # 不同数据集的标记样式
          

          
# 初始化存储结果
          
results = {}
          
for dataset in datasets:
          
    data = results_with_ci_df.loc[dataset]
          
    odds_ratios, ci_lower, ci_upper = [], [], []
          
    for value in data:
          
        odds, lower, upper = extract_ci(value)
          
        odds_ratios.append(odds)
          
        ci_lower.append(lower)
          
        ci_upper.append(upper)
          
    results[dataset] = {
          
        "features": data.index.tolist(),
          
        "odds_ratios": np.array(odds_ratios),
          
        "ci_lower": np.array(ci_lower),
          
        "ci_upper": np.array(ci_upper)
          
    }
          
# 绘图
          
fig, ax = plt.subplots(figsize=(10, 8))
          
y_pos = np.arange(len(results["Training Set"]["features"]))
          

          
# 设置不同数据集的颜色和标记
          
colors = {"Training Set": "lightblue", "Validation Set": "lightgreen", "Testing Set": "lightcoral"}
          
markers = {"Training Set": "o", "Validation Set": "s", "Testing Set": "D"}
          

          
# 绘制三个数据集的误差条和圆圈
          
for i, dataset in enumerate(datasets):
          
    data = results[dataset]
          
    scaled_markersize = max_size - (data["odds_ratios"] / np.max(data["odds_ratios"])) * (max_size - min_size)
          
    
          
    # 由于是同一指标,y轴位置需要做微小偏移
          
    y_offset = 0.2 * (i - 1)  # 偏移量:-0.2, 0, 0.2
          
    for j in range(len(data["features"])):
          
        ax.errorbar(data["odds_ratios"][j], y_pos[j] + y_offset, 
          
                    xerr=[[data["odds_ratios"][j] - data["ci_lower"][j]], 
          
                          [data["ci_upper"][j] - data["odds_ratios"][j]]],
          
                    fmt=markers[dataset], color=colors[dataset], ecolor=colors[dataset],
          
                    capsize=5, capthick=2, markersize=np.sqrt(scaled_markersize[j]))
          

          
# 设置Y轴
          
ax.set_yticks(y_pos)
          
ax.set_yticklabels(results["Training Set"]["features"])  # 所有数据集的指标一致
          
ax.invert_yaxis()
          

          
# 设置标题和标签
          
ax.set_xlabel('Evaluation Metrics (95% CI)')
          
ax.set_title('Model Evaluation Metrics: Random Forest')
          

          
# 添加参考线
          
plt.axvline(x=1, linestyle='--', color='grey', linewidth=1)
          

          
# 添加图例
          
handles = [plt.Line2D([0], [0], color=colors[name], marker=markers[name], linestyle='',
          
                      markersize=10, label=name) for name in datasets]
          
ax.legend(handles=handles, title="Dataset", loc="upper left")
          

          
# 美化图表
          
plt.tight_layout()
          
plt.savefig('Model_Evaluation_Metrics_Random_Forest_Aligned.pdf', format='pdf', bbox_inches='tight', dpi=1200)
          
plt.show()
      

picture.image

将训练集、验证集和测试集的模型评价指标及其置信区间绘制在同一张图表中,并通过对Y轴的微小偏移(y_offset)将不同数据集的相同指标错开排列,同时使用不同颜色和标记区分数据集,使得不同数据集的指标表现更直观地比较

往期推荐

从模型构建到在线部署:基于Stacking集成模型的全流程实现与SHAP可视化

探究SHAP交互效应:基于shap.dependence_plot与自定义可视化方法的对比分析

利用Optuna TPE算法优化RF模型及3D曲面图展示调参过程

nature medicine二分类结局随机森林模型构建与评估复现

期刊配图:分类变量SHAP值的箱线图及可视化优化展示

如何用SHAP解读集成学习Stacking中的基学习器和元学习器以及整体模型贡献

从入门到实践:如何利用Stacking集成多种机器学习算法提高模型性能

整合数据分布+拟合线+置信区间+相关系数的皮尔逊相关可视化

期刊配图:通过变量热图展示样本与模型预测的关联信息

期刊配图:如何有效呈现回归、分类模型的评价指标

picture.image

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
相关资源
CV 技术在视频创作中的应用
本次演讲将介绍在拍摄、编辑等场景,我们如何利用 AI 技术赋能创作者;以及基于这些场景,字节跳动积累的领先技术能力。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论