摘要模型评估是机器学习工作流程中的核心环节选择合适的评估指标直接影响模型优化的方向与最终效果。本文系统梳理了分类、回归两大任务场景下的核心评估指标从混淆矩阵出发深入讲解准确率、精确率、召回率、F1分数等分类指标的理论意义与代码实现详细阐述ROC曲线与AUC的原理、绘制方法及阈值选择策略对比PR曲线在不同数据分布下的适用性并涵盖MAE、MSE、RMSE、R²、MAPE等回归指标的含义与Python实现。通过完整的Scikit-learn代码示例帮助读者快速掌握模型评估的实战技巧。关键词机器学习模型评估混淆矩阵ROC曲线AUCF1分数scikit-learn1. 引言机器学习的核心目标是构建能够泛化到新数据的模型而模型评估正是检验这一目标是否达成的关键步骤。无论是经典的监督学习还是新兴的深度学习模型评估指标都是连接训练过程与实际应用的桥梁。一个看似准确率99%的模型可能因为数据不平衡而毫无价值一个AUC为0.5的分类器可能在特定阈值下成为业务利器。因此深入理解各类评估指标的内涵与适用场景是每一位机器学习从业者的必修课。本文将按照分类任务与回归任务两大类别系统讲解主流评估指标的数学原理并通过scikit-learn给出完整代码示例。读者可根据自身业务场景快速定位并上手适用的评估方法。2. 分类评估指标2.1 混淆矩阵所有指标的基石混淆矩阵Confusion Matrix是二分类问题评估的核心工具以矩阵形式直观展示模型预测与真实标签的对照关系。矩阵的每一行代表模型预测的类别每一列代表真实类别。对于二分类问题混淆矩阵的结构如下预测为正类预测为负类实际为正类TP真正例FN假负例实际为负类FP假正例TN真负例四个基本概念定义如下TPTrue Positive实际为正预测为正——预测正确FPFalse Positive实际为负预测为正——漏诊负类误报FNFalse Negative实际为正预测为负——漏诊正类漏报TNTrue Negative实际为负预测为负——预测正确# Python代码示例混淆矩阵的构建与可视化 import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report ​ # 1. 生成模拟的二分类数据集 # n_samples5000样本数量5000 # n_features20特征数量20 # n_informative15有信息量的特征数量15 # n_redundant5冗余特征数量5 # weights[0.9, 0.1]类别权重负类占90%正类占10%模拟不平衡数据 X, y make_classification( n_samples5000, n_features20, n_informative15, n_redundant5, weights[0.9, 0.1], # 不平衡数据集正类仅占10% random_state42 ) ​ # 2. 划分训练集和测试集 # test_size0.330%作为测试集 # random_state42保证结果可复现 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) ​ # 3. 训练逻辑回归模型 model LogisticRegression(max_iter1000, random_state42) model.fit(X_train, y_train) ​ # 4. 在测试集上预测 y_pred model.predict(X_test) ​ # 5. 计算混淆矩阵 # confusion_matrix 返回值顺序: [[TN, FP], [FN, TP]] cm confusion_matrix(y_test, y_pred) print(混淆矩阵:) print(cm) # 输出示例: # [[1345 32] # [ 98 25]] # TN1345, FP32, FN98, TP25 ​ # 6. 可视化混淆矩阵 # titles_options: 可选多种显示格式 fig, axes plt.subplots(1, 2, figsize(14, 5)) ​ # 左图带数值标签的混淆矩阵 disp ConfusionMatrixDisplay(confusion_matrixcm, display_labels[负类(0), 正类(1)]) disp.plot(axaxes[0], cmapBlues) axes[0].set_title(混淆矩阵数值标签, fontsize14) ​ # 右图归一化后的混淆矩阵每个单元格表示占比 cm_normalized cm.astype(float) / cm.sum(axis1)[:, np.newaxis] disp_norm ConfusionMatrixDisplay(confusion_matrixcm_normalized, display_labels[负类(0), 正类(1)]) disp_norm.plot(axaxes[1], cmapBlues) axes[1].set_title(混淆矩阵按行归一化, fontsize14) ​ plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150, bbox_inchestight) plt.show() ​ # 7. 打印详细分类报告包含各类指标的精确值 # classification_report 输出每个类别的 Precision/Recall/F1-Score/Support print(\n分类报告:) print(classification_report(y_test, y_pred, target_names[负类(0), 正类(1)]))运行上述代码后将得到混淆矩阵的热力图与标准化矩阵从图中可直观看出虽然整体准确率较高因负类样本占主导但正类的召回率极低说明模型对少数类的识别能力严重不足。2.2 准确率Accuracy公式$$Accuracy \frac{TP TN}{TP TN FP FN}$$准确率是最直观、最常用的分类指标表示所有预测中正确预测的比例。其取值范围为[0, 1]值越接近1表示模型越好。然而准确率在数据不平衡场景下具有严重的欺骗性。例如癌症筛查数据中阳性率仅1%模型即使把所有样本都预测为阴性准确率也能达到99%但这毫无意义。from sklearn.metrics import accuracy_score ​ # 计算准确率 acc accuracy_score(y_test, y_pred) print(f准确率 (Accuracy): {acc:.4f}) # 说明在不平衡数据集下99%的准确率可能掩盖正类召回率仅10%的问题使用场景数据类别相对平衡各类别样本比例相近时准确率是快速评估模型整体性能的不错选择。但面对不平衡数据务必结合其他指标综合判断。2.3 精确率Precision公式$$Precision \frac{TP}{TP FP} \frac{预测为正类中实际为正类的数量}{所有预测为正类的数量}$$精确率衡量的是预测为正的样本中有多少是真正的正类。它反映的是模型不误报的能力。在推荐系统中精确率高意味着推荐的内容用户大多确实感兴趣在垃圾邮件检测中精确率高意味着被标记为垃圾邮件的邮件确实是垃圾邮件。from sklearn.metrics import precision_score ​ # 计算精确率 # zero_division0防止分母为0时出现警告 prec precision_score(y_test, y_pred, zero_division0) print(f精确率 (Precision): {prec:.4f})使用场景当误报代价高时优先关注精确率。例如股票推荐系统误推荐一只会跌的股票给用户会造成直接经济损失医疗诊断误诊一个健康人为患者会导致不必要的进一步检查和患者焦虑2.4 召回率Recall / Sensitivity公式$$Recall \frac{TP}{TP FN} \frac{预测为正类中实际为正类的数量}{所有实际为正类的数量}$$召回率衡量的是所有正类样本中模型成功识别出了多少。它反映的是模型不漏报的能力。召回率高意味着尽可能把所有正类样本都找出来。from sklearn.metrics import recall_score ​ # 计算召回率 rec recall_score(y_test, y_pred, zero_division0) print(f召回率 (Recall): {rec:.4f})使用场景当漏报代价高时优先关注召回率。例如癌症筛查漏检一个真正的癌症患者可能导致延误治疗代价极高欺诈检测漏掉一笔欺诈交易可能造成重大经济损失地震预测即使误报也不能漏报召回率至关重要2.5 F1分数F1-Score精确率和召回率往往是一对矛盾体——追求高精确率意味着模型更保守只预测非常有把握的正类这会导致召回率下降反之亦然。F1分数正是为调和这一矛盾而设计的。公式$$F1 \frac{2 \times Precision \times Recall}{Precision Recall}$$F1是精确率和召回率的调和平均数相比简单算术平均它更重视两者的平衡。只有当精确率和召回率都较高时F1才会高。from sklearn.metrics import f1_score ​ # 计算F1分数 f1 f1_score(y_test, y_pred, zero_division0) print(fF1分数 (F1-Score): {f1:.4f})F1的更一般形式是Fβ分数允许通过β调节对召回率的重视程度$$F_\beta (1 \beta^2) \times \frac{Precision \times Recall}{\beta^2 \times Precision Recall}$$β 1更重视精确率如F0.5β 1精确率和召回率同等重要F1β 1更重视召回率如F2from sklearn.metrics import fbeta_score ​ # 计算F2分数召回率的权重更高 # 在医疗检测等场景F2分数比F1更常用 f2 fbeta_score(y_test, y_pred, beta2, zero_division0) print(fF2分数 (F2-Score): {f2:.4f})2.6 特异性Specificity公式$$Specificity \frac{TN}{TN FP} \frac{预测为负类中实际为负类的数量}{所有实际为负类的数量}$$特异性衡量的是模型正确识别负类的能力与召回率敏感度相对应。在医学检测中特异性高意味着健康人不会被误诊为患者。# 手动计算特异性 # 从混淆矩阵中提取 TN, FP tn, fp, fn, tp confusion_matrix(y_test, y_pred).ravel() specificity tn / (tn fp) print(f特异性 (Specificity): {specificity:.4f}) # 或者用 sklearn 的 recall_scorepos_label 参数指定为负类 specificity_sklearn recall_score(y_test, y_pred, pos_label0) print(f特异性 (使用sklearn): {specificity_sklearn:.4f})2.7 敏感度Sensitivity敏感度Sensitivity与召回率Recall是同一概念都是指TPRTrue Positive Rate$$Sensitivity TPR \frac{TP}{TP FN}$$# 敏感度与召回率等价 sensitivity recall_score(y_test, y_pred) print(f敏感度 (Sensitivity): {sensitivity:.4f})3. ROC曲线与AUC3.1 TPR与FPR在深入ROC曲线之前需要先理解两个核心概念TPRTrue Positive Rate 召回率 敏感度所有正类中被正确识别的比例FPRFalse Positive Rate所有负类中被错误识别为正类的比例$$FPR \frac{FP}{FP TN}$$ROC曲线Receiver Operating Characteristic Curve正是以FPR为横轴TPR为纵轴展示模型在不同分类阈值下的表现。# 概念说明手动计算不同阈值下的 TPR 和 FPR y_scores model.predict_proba(X_test)[:, 1] # 获取正类的预测概率 ​ # 手动计算 ROC 曲线上的一些点 thresholds [0.1, 0.3, 0.5, 0.7, 0.9] for thresh in thresholds: # 大于阈值为正类 y_pred_thresh (y_scores thresh).astype(int) tp np.sum((y_pred_thresh 1) (y_test 1)) fp np.sum((y_pred_thresh 1) (y_test 0)) tn np.sum((y_pred_thresh 0) (y_test 0)) fn np.sum((y_pred_thresh 0) (y_test 1)) tpr tp / (tp fn) if (tp fn) 0 else 0 fpr fp / (fp tn) if (fp tn) 0 else 0 print(f阈值{thresh:.1f}: TPR{tpr:.4f}, FPR{fpr:.4f})3.2 ROC曲线绘制from sklearn.metrics import roc_curve, auc, roc_auc_score import matplotlib.pyplot as plt ​ # 1. 获取预测概率而非直接预测标签 # predict_proba 返回每行样本属于各类别的概率第2列是正类(1)的概率 y_prob model.predict_proba(X_test)[:, 1] ​ # 2. 计算不同阈值下的 FPR 和 TPR # fpr, tpr, thresholds分别为假正率、真正率和对应阈值 fpr_arr, tpr_arr, thresholds roc_curve(y_test, y_prob) ​ # 3. 计算AUC值 # AUC是ROC曲线下的面积取值范围[0, 1] auc_score auc(fpr_arr, tpr_arr) print(fAUC值: {auc_score:.4f}) ​ # 也可以直接用 roc_auc_score输入真实标签和预测概率 auc_direct roc_auc_score(y_test, y_prob) print(fAUC值 (直接计算): {auc_direct:.4f}) ​ # 4. 绘制ROC曲线 plt.figure(figsize(8, 6)) plt.plot(fpr_arr, tpr_arr, colordarkorange, lw2, labelfROC曲线 (AUC {auc_score:.4f})) plt.plot([0, 1], [0, 1], colornavy, lw2, linestyle--, label随机猜测 (AUC 0.5)) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(假正率 (FPR), fontsize12) plt.ylabel(真正率 (TPR), fontsize12) plt.title(ROC曲线, fontsize14) plt.legend(loclower right, fontsize11) plt.grid(alpha0.3) ​ # 标注一些关键阈值点 for i in range(0, len(thresholds), len(thresholds)//5): if thresholds[i] 1: plt.annotate(f阈值{thresholds[i]:.2f}, (fpr_arr[i], tpr_arr[i]), textcoordsoffset points, xytext(5, -10), fontsize9, arrowpropsdict(arrowstyle-, colorgray)) ​ plt.tight_layout() plt.savefig(roc_curve.png, dpi150, bbox_inchestight) plt.show()3.3 AUC的含义AUCArea Under the Curve即ROC曲线下的面积其核心含义是随机从正负样本中各抽取一个正类样本的预测分数高于负类样本预测分数的概率。AUC 1.0完美分类器理想情况不存在AUC 0.5随机猜测等同于无分辨能力AUC 0.5比随机猜测还差说明模型预测方向反了可通过反转预测结果来改善AUC的特点不受阈值影响AUC描述的是模型在所有阈值下的整体排序能力而非某个特定阈值下的表现对数据不平衡不敏感由于只看相对排序不受正负样本比例影响衡量模型区分能力本质上AUC评估的是模型区分正负样本的能力# AUC的另一个理解正样本score 负样本score 的概率 # 验证计算 pos_scores y_prob[y_test 1] neg_scores y_prob[y_test 0] # 计算正样本分数大于负样本分数的比例 count 0 total len(pos_scores) * len(neg_scores) for p in pos_scores: for n in neg_scores: if p n: count 1 auc_manual count / total print(fAUC (手动验证): {auc_manual:.4f})3.4 如何选择最佳阈值ROC曲线上的每个点对应一个分类阈值。选择最佳阈值需要权衡TPR和FPR常用方法包括方法一Youdens J统计量$$J TPR - FPR$$选择使J值最大的阈值即ROC曲线上距离对角线最远的点。# 使用 Youdens J 统计量选择最佳阈值 j_scores tpr_arr - fpr_arr best_idx np.argmax(j_scores) best_threshold thresholds[best_idx] best_tpr tpr_arr[best_idx] best_fpr fpr_arr[best_idx] ​ print(f最佳阈值 (Youdens J): {best_threshold:.4f}) print(f对应 TPR: {best_tpr:.4f}, FPR: {best_fpr:.4f})方法二几何平均G-Mean$$G\text{-}Mean \sqrt{TPR \times Specificity}$$G-Mean综合考虑正类和负类的识别率在不平衡数据集上表现良好。# 使用 G-Mean 选择最佳阈值 specificity_arr 1 - fpr_arr g_means np.sqrt(tpr_arr * specificity_arr) best_g_idx np.argmax(g_means) best_g_threshold thresholds[best_g_idx] ​ print(f最佳阈值 (G-Mean): {best_g_threshold:.4f}) print(f对应 TPR: {tpr_arr[best_g_idx]:.4f}, Specificity: {specificity_arr[best_g_idx]:.4f})4. PR曲线4.1 什么是PR曲线PR曲线Precision-Recall Curve以召回率为横轴精确率为纵轴展示不同阈值下两者之间的权衡关系。相比ROC曲线PR曲线更能反映模型在不平衡数据集上的真实表现。from sklearn.metrics import precision_recall_curve, average_precision_score from sklearn.metrics import auc ​ # 1. 计算PR曲线 # 返回不同阈值下的精确率、召回率和对应阈值 precision_arr, recall_arr, pr_thresholds precision_recall_curve(y_test, y_prob) ​ # 2. 计算PR曲线下面积Average Precision # AP是PR曲线下面积的近似等效于AUC在PR空间中的值 ap_score average_precision_score(y_test, y_prob) print(f平均精确率 (Average Precision): {ap_score:.4f}) ​ # 3. 绘制PR曲线 plt.figure(figsize(8, 6)) plt.plot(recall_arr, precision_arr, colorgreen, lw2, labelfPR曲线 (AP {ap_score:.4f})) ​ # 标注基线正类比例 baseline np.sum(y_test) / len(y_test) plt.axhline(ybaseline, colorred, linestyle--, lw1.5, labelf基线 (正类比例 {baseline:.4f})) ​ plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(召回率 (Recall), fontsize12) plt.ylabel(精确率 (Precision), fontsize12) plt.title(精确率-召回率曲线 (PR Curve), fontsize14) plt.legend(locupper right, fontsize11) plt.grid(alpha0.3) plt.tight_layout() plt.savefig(pr_curve.png, dpi150, bbox_inchestight) plt.show()4.2 为什么PR曲线在不平衡数据下更可靠当数据集严重不平衡时ROC曲线的FPR分母TNFP中TN占主导导致FPR变化不明显ROC曲线的变化不足以反映模型对少数类的识别能力变化。而PR曲线直接以精确率和召回率为坐标更敏感地反映少数类的表现。# 对比在极度不平衡数据下ROC和PR曲线的差异 # 生成极度不平衡数据正类仅占1% X_imbalanced, y_imbalanced make_classification( n_samples10000, n_features20, n_informative10, weights[0.99, 0.01], # 1%正类 random_state42 ) ​ X_train_imb, X_test_imb, y_train_imb, y_test_imb train_test_split( X_imbalanced, y_imbalanced, test_size0.3, random_state42, stratifyy_imbalanced ) ​ model_imb LogisticRegression(max_iter1000, random_state42) model_imb.fit(X_train_imb, y_train_imb) y_prob_imb model_imb.predict_proba(X_test_imb)[:, 1] ​ # 计算 ROC AUC 和 PR AUC roc_auc_imb roc_auc_score(y_test_imb, y_prob_imb) ap_imb average_precision_score(y_test_imb, y_prob_imb) ​ print(f极度不平衡数据 - ROC AUC: {roc_auc_imb:.4f}) print(f极度不平衡数据 - Average Precision (PR AUC): {ap_imb:.4f}) ​ # PR曲线的AP很低说明模型在少数类上的精确率和召回率都很差 # 而ROC AUC看起来可能还不错因为FPR变化不大5. 回归评估指标回归任务评估的是模型预测的连续值与真实值之间的误差。以下是常用的回归评估指标。5.1 MAE平均绝对误差公式$$MAE \frac{1}{n} \sum{i1}^{n} |y_i - \hat{y}i|$$MAE是预测值与真实值之差的绝对值的平均对所有误差赋予相同权重对异常值相对稳健。from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np ​ # 生成回归数据集 from sklearn.datasets import make_regression X_reg, y_reg make_regression( n_samples1000, n_features10, noise20, random_state42 ) ​ X_train_reg, X_test_reg, y_train_reg, y_test_reg train_test_split( X_reg, y_reg, test_size0.3, random_state42 ) ​ # 训练一个简单的回归模型 from sklearn.linear_model import LinearRegression reg_model LinearRegression() reg_model.fit(X_train_reg, y_train_reg) y_pred_reg reg_model.predict(X_test_reg) ​ # 1. MAE平均绝对误差 mae mean_absolute_error(y_test_reg, y_pred_reg) print(fMAE (平均绝对误差): {mae:.4f}) ​ # 手动验证 mae_manual np.mean(np.abs(y_test_reg - y_pred_reg)) print(fMAE (手动验证): {mae_manual:.4f})5.2 MSE均方误差公式$$MSE \frac{1}{n} \sum{i1}^{n} (y_i - \hat{y}i)^2$$MSE对较大的误差给予更大的惩罚因为平方项放大了大误差的影响但对异常值敏感。# 2. MSE均方误差 mse mean_squared_error(y_test_reg, y_pred_reg) print(fMSE (均方误差): {mse:.4f}) ​ # 手动验证 mse_manual np.mean((y_test_reg - y_pred_reg) ** 2) print(fMSE (手动验证): {mse_manual:.4f})5.3 RMSE均方根误差公式$$RMSE \sqrt{MSE} \sqrt{\frac{1}{n} \sum{i1}^{n} (y_i - \hat{y}i)^2}$$RMSE是MSE的平方根与目标变量具有相同的单位更容易解释。在物理和工程领域RMSE比MSE更常用。# 3. RMSE均方根误差 rmse np.sqrt(mse) print(fRMSE (均方根误差): {rmse:.4f}) ​ # sklearn 直接计算 rmse_sklearn mean_squared_error(y_test_reg, y_pred_reg, squaredFalse) print(fRMSE (sklearn): {rmse_sklearn:.4f})5.4 R²决定系数公式$$R^2 1 - \frac{\sum{i1}^{n}(y_i - \hat{y}i)^2}{\sum{i1}^{n}(y_i - \bar{y})^2} 1 - \frac{SS{res}}{SS_{tot}}$$R²表示模型对目标变量变异性的解释程度取值范围通常为[0, 1]在OLS框架下但也可能为负当模型预测比简单均值还差时。R² 1模型完美预测R² 0模型预测效果与简单均值预测相当R² 0模型完全失效预测不如均值# 4. R²决定系数 r2 r2_score(y_test_reg, y_pred_reg) print(fR² (决定系数): {r2:.4f}) ​ # 手动验证 ss_res np.sum((y_test_reg - y_pred_reg) ** 2) # 残差平方和 ss_tot np.sum((y_test_reg - np.mean(y_test_reg)) ** 2) # 总平方和 r2_manual 1 - (ss_res / ss_tot) print(fR² (手动验证): {r2_manual:.4f}) ​ # 说明R²0.85意味着模型解释了85%的目标变量方差5.5 MAPE平均绝对百分比误差公式$$MAPE \frac{100\%}{n} \sum{i1}^{n} \left| \frac{y_i - \hat{y}i}{y_i} \right|$$MAPE以百分比形式表示预测误差适合业务报告和跨场景比较。但当真实值接近0时MAPE会趋向无穷大需要特殊处理。# 5. MAPE平均绝对百分比误差 # 注意MAPE在sklearn中需要手动计算 def mean_absolute_percentage_error(y_true, y_pred): 计算MAPE处理y_true中含0的情况 y_true, y_pred np.array(y_true), np.array(y_pred) # 避免除以0只计算非零样本的MAPE non_zero_mask y_true ! 0 return np.mean(np.abs((y_true[non_zero_mask] - y_pred[non_zero_mask]) / y_true[non_zero_mask])) * 100 ​ mape mean_absolute_percentage_error(y_test_reg, y_pred_reg) print(fMAPE (平均绝对百分比误差): {mape:.4f}%) ​ # 注意MAPE的缺点是当真实值接近0时会变得非常大 # 解决方法是使用对称MAPESMAPE或在真实值极小时限制计算范围5.6 回归指标对比与选择# 综合对比所有回归指标 print( * 50) print(回归指标综合对比) print( * 50) print(fMAE (平均绝对误差): {mae:.4f}) print(fMSE (均方误差): {mse:.4f}) print(fRMSE (均方根误差): {rmse:.4f}) print(fR² (决定系数): {r2:.4f}) print(fMAPE (平均绝对百分比误差): {mape:.4f}%) print( * 50) ​ # 指标解读 print(\n指标选择指南) print(- MAE误差量纲相同对异常值稳健适合评估典型误差) print(- MSE惩罚大误差适合大错代价高的场景如金融风险) print(- RMSE与MAE相同量纲适合报告和业务沟通) print(- R²衡量模型解释力0.7-0.9通常为较好水平) print(- MAPE适合跨尺度比较但不适合同比接近0的数据)6. 实战综合评估示例下面通过一个完整的实战案例展示如何针对不同业务场景选择合适的评估指标。# 综合实战多模型对比与指标选择 from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split, cross_val_predict from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC from sklearn.metrics import ( confusion_matrix, accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, average_precision_score, classification_report, roc_curve, precision_recall_curve ) import matplotlib.pyplot as plt import numpy as np ​ # 1. 准备不平衡数据集模拟实际业务场景 X, y make_classification( n_samples5000, n_features20, n_informative15, n_redundant5, weights[0.85, 0.15], # 15%正类 random_state42 ) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) ​ # 2. 定义三个不同类型的模型 models { 逻辑回归: LogisticRegression(max_iter1000, random_state42), 随机森林: RandomForestClassifier(n_estimators100, random_state42), SVM: SVC(kernelrbf, probabilityTrue, random_state42) } ​ # 3. 存储评估结果 results {} ​ # 4. 对每个模型进行评估 for name, model in models.items(): print(f\n{*50}) print(f模型: {name}) print(*50) # 训练模型 model.fit(X_train, y_train) # 获取预测结果 y_pred model.predict(X_test) y_prob model.predict_proba(X_test)[:, 1] # 计算各项指标 cm confusion_matrix(y_test, y_pred) tn, fp, fn, tp cm.ravel() accuracy accuracy_score(y_test, y_pred) precision precision_score(y_test, y_pred, zero_division0) recall recall_score(y_test, y_pred, zero_division0) f1 f1_score(y_test, y_pred, zero_division0) specificity tn / (tn fp) roc_auc roc_auc_score(y_test, y_prob) ap average_precision_score(y_test, y_prob) # 存储结果 results[name] { Accuracy: accuracy, Precision: precision, Recall: recall, F1: f1, Specificity: specificity, ROC_AUC: roc_auc, AP: ap, y_prob: y_prob } # 打印详细报告 print(f混淆矩阵: TN{tn}, FP{fp}, FN{fn}, TP{tp}) print(f准确率 (Accuracy): {accuracy:.4f}) print(f精确率 (Precision): {precision:.4f}) print(f召回率 (Recall): {recall:.4f}) print(fF1分数 (F1-Score): {f1:.4f}) print(f特异性 (Specificity): {specificity:.4f}) print(fROC_AUC: {roc_auc:.4f}) print(fAP (PR_AUC): {ap:.4f}) print(f\n详细分类报告:) print(classification_report(y_test, y_pred, target_names[负类, 正类], zero_division0)) ​ # 5. 汇总对比表格 print(\n *80) print(模型综合对比汇总) print(*80) print(f{模型:15} {Acc:8} {Prec:8} {Rec:8} {F1:8} {Spec:8} {AUC:8} {AP:8}) print(-*80) for name, metrics in results.items(): print(f{name:15} {metrics[Accuracy]:8.4f} {metrics[Precision]:8.4f} f{metrics[Recall]:8.4f} {metrics[F1]:8.4f} {metrics[Specificity]:8.4f} f{metrics[ROC_AUC]:8.4f} {metrics[AP]:8.4f}) print(*80) ​ # 6. 绘制对比图 fig, axes plt.subplots(2, 2, figsize(14, 12)) ​ # 6.1 ROC曲线对比 ax1 axes[0, 0] colors [blue, green, red] for (name, metrics), color in zip(results.items(), colors): fpr, tpr, _ roc_curve(y_test, metrics[y_prob]) ax1.plot(fpr, tpr, colorcolor, lw2, labelf{name} (AUC{metrics[ROC_AUC]:.4f})) ax1.plot([0, 1], [0, 1], k--, lw1) ax1.set_xlabel(FPR) ax1.set_ylabel(TPR) ax1.set_title(ROC曲线对比) ax1.legend() ax1.grid(alpha0.3) ​ # 6.2 PR曲线对比 ax2 axes[0, 1] for (name, metrics), color in zip(results.items(), colors): precision, recall, _ precision_recall_curve(y_test, metrics[y_prob]) ax2.plot(recall, precision, colorcolor, lw2, labelf{name} (AP{metrics[AP]:.4f})) baseline np.sum(y_test) / len(y_test) ax2.axhline(ybaseline, colorgray, linestyle--, labelf基线{baseline:.4f}) ax2.set_xlabel(Recall) ax2.set_ylabel(Precision) ax2.set_title(PR曲线对比) ax2.legend() ax2.grid(alpha0.3) ​ # 6.3 指标柱状图 ax3 axes[1, 0] metrics_to_plot [Precision, Recall, F1, AP] x np.arange(len(metrics_to_plot)) width 0.25 for i, (name, metrics) in enumerate(results.items()): values [metrics[m] for m in metrics_to_plot] ax3.bar(x i*width, values, width, labelname, colorcolors[i], alpha0.8) ax3.set_xticks(x width) ax3.set_xticklabels(metrics_to_plot) ax3.set_ylabel(分数) ax3.set_title(分类指标对比) ax3.legend() ax3.grid(alpha0.3, axisy) ​ # 6.4 指标雷达图 ax4 axes[1, 1] ax4.axis(off) # 用表格替代雷达图雷达图在sklearn外需额外库 cell_text [] for name, metrics in results.items(): cell_text.append([ f{metrics[Accuracy]:.3f}, f{metrics[Precision]:.3f}, f{metrics[Recall]:.3f}, f{metrics[F1]:.3f}, f{metrics[Specificity]:.3f}, f{metrics[ROC_AUC]:.3f}, f{metrics[AP]:.3f} ]) table ax4.table( cellTextcell_text, rowLabelslist(results.keys()), colLabels[Acc, Prec, Rec, F1, Spec, AUC, AP], cellLoccenter, rowLoccenter, loccenter, bbox[0.1, 0.3, 0.8, 0.5] ) table.auto_set_font_size(False) table.set_fontsize(10) table.scale(1.2, 1.5) ax4.set_title(指标汇总表, fontsize12, pad20) ​ plt.tight_layout() plt.savefig(model_comparison.png, dpi150, bbox_inchestight) plt.show()7. 指标选择指南不同业务场景下评估指标的侧重点各有不同。以下是常见场景的指标推荐7.1 分类任务场景主要指标次要指标说明类别平衡数据AccuracyF1, ROC_AUC各类别样本比例相近时准确率即可反映整体性能不平衡数据少数类重要Recall / F1ROC_AUC, AP如疾病筛查、欺诈检测漏报代价高不平衡数据误报代价高PrecisionF1, ROC_AUC如推荐系统、垃圾邮件过滤排序任务ROC_AUCAP只关心正类排在负类前面的概率极度不平衡PR_AUC (AP)RecallROC曲线在极度不平衡下可能过于乐观需要综合权衡F1 / Fβ-需要同时控制误报和漏报7.2 回归任务指标特点适用场景MAE对异常值稳健量纲与目标变量一致典型误差评估、成本预测MSE惩罚大误差对异常值敏感金融风险、重大偏差不可接受场景RMSE与MAE同量纲易解释物理工程领域、报告与沟通R²衡量模型解释力与数据尺度无关模型解释力评估、论文报告MAPE百分比形式跨尺度可比业务报告、需求预测8. 总结本文系统梳理了机器学习中分类与回归两大任务的核心评估指标分类任务从混淆矩阵出发理解TP/FP/TN/FN四个基本概念是掌握所有分类指标的关键。精确率与召回率的平衡是分类评估的核心挑战F1分数提供了折中方案ROC-AUC从全局排序能力角度评估模型在数据不平衡时比准确率更可靠PR曲线则在极度不平衡场景下提供更准确的性能画像。回归任务MAE、MSE、RMSE从不同角度刻画预测误差R²反映模型的解释力MAPE以百分比形式便于跨场景比较。实战要点没有万能指标必须结合业务场景和数据特点选择合适的评估体系。数据不平衡时尤其需要谨慎避免被单一准确率误导。理解每个指标的数学本质与适用边界才能在模型开发中做出正确的优化方向决策真正发挥机器学习模型的价值。