从混淆矩阵到AUC:5步代码实战绘制ROC与PR曲线对比

📅 2026/7/5 12:11:21
从混淆矩阵到AUC:5步代码实战绘制ROC与PR曲线对比
从混淆矩阵到AUC5步代码实战绘制ROC与PR曲线对比在机器学习模型的评估过程中分类性能的量化分析是核心环节。传统理论讲解往往让初学者陷入公式迷宫而本文将带您通过5个可执行的代码步骤从混淆矩阵基础出发最终完成ROC与PR曲线的对比可视化并深入解读AUC/AP值的实际意义。1. 环境准备与模拟数据生成任何模型评估都需要标准化的测试环境。我们首先生成一个适用于二分类问题的模拟数据集确保正负样本比例可控3:7以模拟真实场景中的类别不均衡情况from sklearn.datasets import make_classification import matplotlib.pyplot as plt import numpy as np # 生成1000个样本特征维度20其中5个为有效特征 X, y make_classification( n_samples1000, n_features20, n_informative5, n_classes2, weights[0.7, 0.3], random_state42 ) # 查看样本分布 print(f负样本数: {sum(y0)}, 正样本数: {sum(y1)})提示通过调整weights参数可以模拟不同程度的类别不平衡这对后续曲线分析至关重要。为验证模型效果我们使用逻辑回归进行训练并输出预测概率而非硬分类结果from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split # 划分训练集与测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42) # 训练模型并获取预测概率 model LogisticRegression(max_iter1000) model.fit(X_train, y_train) y_scores model.predict_proba(X_test)[:, 1] # 取正类概率2. 混淆矩阵的动态构建混淆矩阵不是静态概念其数值随分类阈值的变化而改变。下面代码展示如何根据阈值动态生成矩阵from sklearn.metrics import confusion_matrix def dynamic_confusion_matrix(y_true, y_scores, threshold0.5): y_pred (y_scores threshold).astype(int) tn, fp, fn, tp confusion_matrix(y_true, y_pred).ravel() return { Threshold: threshold, TP: tp, FP: fp, TN: tn, FN: fn, Precision: tp/(tpfp) if (tpfp)0 else 0, Recall: tp/(tpfn) if (tpfn)0 else 0 } # 测试不同阈值下的矩阵变化 thresholds [0.2, 0.5, 0.8] for thresh in thresholds: print(f阈值{thresh}:, dynamic_confusion_matrix(y_test, y_scores, thresh))输出示例阈值0.2: {Threshold: 0.2, TP: 82, FP: 147, TN: 153, FN: 18, Precision: 0.358, Recall: 0.82} 阈值0.5: {Threshold: 0.5, TP: 65, FP: 45, TN: 255, FN: 35, Precision: 0.591, Recall: 0.65} 阈值0.8: {Threshold: 0.8, TP: 28, FP: 5, TN: 295, FN: 72, Precision: 0.848, Recall: 0.28}关键观察点阈值降低召回率上升但精确率下降捕获更多正例代价是误报增加阈值升高精确率提升但召回率降低预测更保守漏检增多3. ROC曲线的生成与解读ROC曲线通过系统遍历所有可能阈值展示模型在不同误报容忍度下的性能。使用sklearn.metrics可快速计算关键指标from sklearn.metrics import roc_curve, auc fpr, tpr, thresholds roc_curve(y_test, y_scores) roc_auc auc(fpr, tpr) # 绘制曲线 plt.figure(figsize(10, 6)) plt.plot(fpr, tpr, colordarkorange, lw2, labelfROC曲线 (AUC {roc_auc:.3f})) plt.plot([0, 1], [0, 1], colornavy, lw2, linestyle--) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(假正例率 (FPR)) plt.ylabel(真正例率 (TPR)) plt.title(ROC曲线分析) plt.legend(loclower right) # 标记最佳阈值点 optimal_idx np.argmax(tpr - fpr) plt.scatter(fpr[optimal_idx], tpr[optimal_idx], markero, colorred) plt.annotate(f最佳阈值: {thresholds[optimal_idx]:.2f}, (fpr[optimal_idx]0.05, tpr[optimal_idx]-0.05)) plt.show()曲线特征解读对角线表示随机猜测模型的性能AUC0.5左上方凸起模型区分能力越强AUC值越高最佳阈值点TPR与FPR差值最大处通常作为业务平衡点4. PR曲线的绘制与对比分析在类别不平衡场景下PR曲线比ROC曲线更能反映模型真实性能。下面是实现代码from sklearn.metrics import precision_recall_curve, average_precision_score precision, recall, _ precision_recall_curve(y_test, y_scores) ap average_precision_score(y_test, y_scores) plt.figure(figsize(10, 6)) plt.plot(recall, precision, colorblue, lw2, labelfPR曲线 (AP {ap:.3f})) plt.xlabel(召回率 (Recall)) plt.ylabel(精确率 (Precision)) plt.title(PR曲线分析) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.legend(locupper right) # 标记平衡点 plt.scatter(recall[optimal_idx], precision[optimal_idx], markero, colorred) plt.annotate(f平衡点: P{precision[optimal_idx]:.2f}, R{recall[optimal_idx]:.2f}, (recall[optimal_idx]0.05, precision[optimal_idx]-0.05)) plt.show()ROC与PR曲线的选择指南场景特征推荐曲线原因分析类别分布均衡ROC整体性能评估更全面负样本远多于正样本PR避免负样本主导评价指标关注假正例成本PR精确率直接反映误报比例需要比较不同模型两者均需综合评估泛化与细分能力5. 关键指标的系统对比与业务应用最后我们整合所有指标形成可落地的业务决策工具from sklearn.metrics import classification_report # 按最佳阈值生成最终预测 y_pred (y_scores thresholds[optimal_idx]).astype(int) # 输出完整评估报告 print(classification_report(y_test, y_pred, target_names[负类, 正类])) # 构建指标对比表格 metrics { AUC: roc_auc, AP: ap, F1: f1_score(y_test, y_pred), Balanced Acc: balanced_accuracy_score(y_test, y_pred) } pd.DataFrame.from_dict(metrics, orientindex, columns[值])典型业务场景的阈值选择策略金融风控低FP容忍选择PR曲线上精确率90%的阈值可接受召回率降低以减少误拦截疾病筛查低FN优先选择ROC曲线上TPR95%的阈值适当放宽FPR以提高病例检出推荐系统平衡体验选择F1分数最大的阈值精确率与召回率的调和平衡# 保存完整评估结果到CSV results pd.DataFrame({ Threshold: thresholds, FPR: fpr, TPR: tpr, Precision: precision[:-1], # 移除最后一个冗余点 Recall: recall[:-1] }) results.to_csv(model_evaluation_metrics.csv, indexFalse)通过这5个步骤我们不仅实现了从理论到实践的跨越更建立了可复用的模型评估框架。在实际项目中建议将此流程封装为Python类方便在不同模型中快速调用对比。