Python 模型评估练习:不只看准确率
评估是模型与决策相遇的地方。一个准确率数字可能掩盖“永远找不到关心类别”的分类器。这些练习先计算混淆矩阵,再从中推导指标。
先划分,再看结果
在选择特征或阈值前留出样本。固定划分容易复现;对有序数据,带固定种子的打乱划分通常更好。绝不要在测试集上调参。
rows = list(range(10))
cut = 7
train, test = rows[:cut], rows[cut:]
print(len(train), len(test))
print(test)固定的留出集
构造混淆矩阵
根据真实和预测标签统计真正例、真负例、假正例和假负例。计算比例前先打印计数;异常的指标往往由一个格子解释。
actual = [1, 1, 0, 0]
predicted = [1, 0, 0, 1]
tp = sum(a == 1 and p == 1 for a, p in zip(actual, predicted))
tn = sum(a == 0 and p == 0 for a, p in zip(actual, predicted))
fp = sum(a == 0 and p == 1 for a, p in zip(actual, predicted))
fn = sum(a == 1 and p == 0 for a, p in zip(actual, predicted))
print(tp, tn, fp, fn)先看四个格子
推导精确率、召回率和 F1
精确率是 tp / (tp + fp),召回率是 tp / (tp + fn),F1 是两者的调和平均。使用防除零的辅助函数,避免“没有预测正例”的分类器让报告崩溃。
tp, fp, fn = 8, 2, 4
precision = tp / (tp + fp) if tp + fp else 0.0
recall = tp / (tp + fn) if tp + fn else 0.0
f1 = 2 * precision * recall / (precision + recall) if precision + recall else 0.0
print(round(precision, 2), round(recall, 2), round(f1, 2))三个相关数字
与简单基线比较
类别不平衡时,全部预测为负也可能有高准确率。把模型与该基线比较,并检查每个类别的召回率。一个从不预测少数类的模型,不会因为 95% 准确率就有用。
actual = [0] * 95 + [1] * 5
predicted = [0] * 100
accuracy = sum(a == p for a, p in zip(actual, predicted)) / len(actual)
print(round(accuracy, 2))
print(sum(1 for a, p in zip(actual, predicted) if a == 1 and p == 1))准确率不够
移动阈值,观察权衡
分类器分数只有在阈值之后才变成标签。提高阈值通常减少假正例、增加假负例。阈值应根据验证数据和真实错误代价选择。
scores = [0.9, 0.6, 0.4, 0.3]
for threshold in (0.5, 0.7):
predicted = [1 if score >= threshold else 0 for score in scores]
print(threshold, predicted)这是决策,不是事实
你的练习清单
- 在选择特征和调参前留出测试数据。
- 先打印混淆矩阵,再计算比例。
- 精确率、召回率和 F1 都要防除零。
- 与多数类基线比较。
- 阈值根据验证数据和错误代价选择。
常见问题
准确率还是 F1?
取决于假正例和假负例的代价。应报告多个指标和类别比例,而不是用一个数字掩盖权衡。
可以用测试集选阈值吗?
不可以。决策使用验证数据,最后再在测试集上报告一次结果。
多少分算好?
没有通用数字。应与基线、可用的人工表现,以及应用中的错误代价比较。
练习模型评估
12 道题,覆盖数据划分、混淆矩阵、精确率、召回率、F1、类别不平衡和阈值。
继续阅读: