在机器学习项目的生命周期中,模型评估往往是最容易被忽视却至关重要的环节。当我们在鸢尾花分类项目中使用随机森林或SVM取得90%的准确率后,真正的挑战才刚刚开始——这个数字究竟意味着什么?各类别的识别率是否均衡?在不同决策阈值下模型表现如何稳定?这些问题仅靠单一指标无法回答,而需要一套完整的可视化评估体系。
混淆矩阵(Confusion Matrix)是理解分类模型行为的起点。与准确率这种"压缩饼干"式的指标不同,混淆矩阵保留了各类别间的预测细节。使用scikit-learn生成混淆矩阵时,建议配合Seaborn的热力图进行可视化:
python复制from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(8,6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names,
yticklabels=class_names)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.title('Confusion Matrix Heatmap')
关键改进点:
annot=True显示具体数值fmt='d'确保显示整数格式class_names参数标注类别名称Blues色系scikit-learn的classification_report提供了精确率、召回率等指标的类别级明细:
python复制from sklearn.metrics import classification_report
print(classification_report(y_true, y_pred,
target_names=class_names))
典型输出示例:
code复制 precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 0.93 0.87 0.90 15
virginica 0.87 0.93 0.90 15
accuracy 0.93 45
macro avg 0.93 0.93 0.93 45
weighted avg 0.93 0.93 0.93 45
解读技巧:
ROC曲线通过动态调整决策阈值,展示真正例率(TPR)与假正例率(FPR)的权衡关系。以下是标准绘制流程:
python复制from sklearn.metrics import roc_curve, auc
# 获取预测概率
y_scores = model.predict_proba(X_test)[:, 1]
# 计算ROC曲线
fpr, tpr, thresholds = roc_curve(y_test, y_scores)
roc_auc = auc(fpr, tpr)
# 绘制曲线
plt.figure(figsize=(8,6))
plt.plot(fpr, tpr, color='darkorange',
lw=2, label=f'AUC = {roc_auc:.2f}')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic')
plt.legend(loc="lower right")
工程实践建议:
predict_proba而非decision_function保证概率校准对于鸢尾花这类多分类问题,可采用以下两种策略:
OvR(One-vs-Rest)方法:
python复制from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
# 二值化标签
y_test_bin = label_binarize(y_test, classes=[0,1,2])
# 使用OvR策略
classifier = OneVsRestClassifier(SVC(probability=True))
classifier.fit(X_train, y_train)
y_score = classifier.predict_proba(X_test)
# 绘制每个类别的ROC曲线
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(3):
fpr[i], tpr[i], _ = roc_curve(y_test_bin[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
plt.plot(fpr[i], tpr[i],
label=f'Class {i} (AUC = {roc_auc[i]:.2f})')
Micro/Macro平均法:
python复制# Micro-average
fpr_micro, tpr_micro, _ = roc_curve(y_test_bin.ravel(), y_score.ravel())
roc_auc_micro = auc(fpr_micro, tpr_micro)
# Macro-average
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(3)]))
mean_tpr = np.zeros_like(all_fpr)
for i in range(3):
mean_tpr += np.interp(all_fpr, fpr[i], tpr[i])
mean_tpr /= 3
roc_auc_macro = auc(all_fpr, mean_tpr)
制作适合汇报的可视化时,需注意:
字体与布局优化:
python复制plt.rcParams.update({
'font.size': 12,
'axes.titlesize': 14,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'figure.titlesize': 16
})
plt.figure(figsize=(10,8))
plt.subplots_adjust(wspace=0.3, hspace=0.3) # 调整子图间距
颜色方案选择:
python复制import matplotlib.colors as mcolors
# 创建感知均匀的色系
colors = list(mcolors.TABLEAU_COLORS.values())
markers = ['o', 's', '^', 'v', '<', '>', 'p', '*']
将多个评估指标整合到同一面板中:
python复制fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16,6))
# 子图1:混淆矩阵
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=ax1)
ax1.set_title('Confusion Matrix')
# 子图2:ROC曲线
for i in range(3):
ax2.plot(fpr[i], tpr[i],
color=colors[i], marker=markers[i],
label=f'Class {i} (AUC={roc_auc[i]:.2f})')
ax2.set_title('ROC Curves')
ax2.legend()
当各类别样本量差异显著时,可采取:
加权AUC计算:
python复制from sklearn.metrics import roc_auc_score
# 按类别样本量加权
class_weights = {0:1.0, 1:2.0, 2:1.5} # 根据实际情况调整
weighted_auc = roc_auc_score(y_test_bin, y_score,
multi_class='ovr',
average='weighted')
过采样技术应用:
python复制from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_res, y_res = smote.fit_resample(X_train, y_train)
某些模型(如SVM)输出的"概率"可能未经校准:
python复制from sklearn.calibration import CalibratedClassifierCV
# 概率校准
calibrated = CalibratedClassifierCV(base_estimator=SVC(),
method='sigmoid',
cv=3)
calibrated.fit(X_train, y_train)
calibrated_probs = calibrated.predict_proba(X_test)
寻找最佳操作点的实用方法:
python复制from sklearn.metrics import f1_score
# 遍历阈值计算F1分数
thresholds = np.linspace(0, 1, 100)
f1_scores = [f1_score(y_test, y_scores[:,1] >= t) for t in thresholds]
optimal_idx = np.argmax(f1_scores)
optimal_threshold = thresholds[optimal_idx]
在模型评估这个领域,我见过太多团队在初期过度关注准确率指标,直到上线后才发现各类别表现严重不均衡。有一次医疗影像分类项目中,模型整体准确率达到95%,但ROC曲线显示对罕见病的识别率几乎为0——这正是可视化评估的价值所在。