2. 混淆矩阵常用指标:准确率、精确率、召回率、特异度
聊完混淆矩阵的基本结构,接下来进入正题——那些我们天天挂在嘴边的指标。说实话,我刚入行那会儿,总把准确率和精确率混着用,结果被review的同事猛批了一顿。嗯,这里要注意:这几个指标虽然都从混淆矩阵里算出来,但它们各自盯的是不同的问题。我把它们归纳成一张图,你先看一眼心里就有谱了。
2.1 准确率(Accuracy)
准确率是最直观的指标——所有样本里,模型猜对了多少。公式很简单:
Accuracy = (TP + TN) / (TP + FP + FN + TN)
但我得提醒一句:这个指标在数据不平衡时特别容易骗人。我记得有一次做宏基因组的物种分类任务,99%的样本都是背景菌,剩下1%是目标病原体。我一看准确率99.2%,高兴得不行,结果模型把所有样本都判成了背景菌——100%的精确率和召回率全是零。你想想看,那准确率有什么意义?
2.2 精确率(Precision)
精确率关心的是:所有被模型判为正类的样本里,有多少是真货?公式:
Precision = TP / (TP + FP)
说白了,就是模型说“这是目标菌”,我信不信它。在宏基因组诊断里,精确率低意味着假阳性太多——你测试出患者感染了某种致病菌,结果lab复查发现是污染或同源序列的误判。我做过一次抗性基因检测项目,精确率才0.6,等于每报10个基因里有4个是假的,那报告谁还敢用?
2.3 召回率(Recall)
召回率又是一个视角:所有真正的正样本里,模型找出来了多少?公式:
Recall = TP / (TP + FN)
召回率低意味着漏检——本来患者体内有致病菌,模型却漏掉了。这在临床上是不可接受的。我参与过一项肠道菌群与癌症标记物的研究,当时模型精确率特别好(几乎没错报),但召回率只有0.3,意味着70%的真实标记菌被我们放跑了。说白了,召回率是“能不能把坏人全抓住”的能力。
这里有个经典的精确率-召回率权衡:调低分类阈值,召回率上升,但精确率往往下降;反之亦然。没有免费的午餐。
2.4 特异度(Specificity)
特异度是召回率的“反面兄弟”——它关注负样本:所有真实的负类样本里,模型正确识别出了多少?公式:
Specificity = TN / (TN + FP)
在宏基因组中,负类通常指背景菌或健康样本中的微生物。特异度低,模型就会把大量正常菌误报为致病菌,造成过度诊断。我印象最深的一次,是某项目用qPCR验证宏基因组结果,因为我们的模型特异度只有0.78,导致后续湿实验浪费了整整三个月的经费去验证假阳性。
准确率 = 全部猜对的比例
精确率 = 猜为正类里真货的比例
召回率 = 真货里被找出的比例
特异度 = 假货里被正确排除的比例
2.5 四指标对比表
| 指标 | 公式 | 关注点 | 宏基因组常见陷阱 |
|---|---|---|---|
| 准确率 | (TP+TN)/(TP+FP+FN+TN) | 全局正确率 | 类别不平衡时虚高 |
| 精确率 | TP/(TP+FP) | 阳性预测值 | 假阳性高导致过度诊断 |
| 召回率 | TP/(TP+FN) | 检测灵敏度 | 漏检致病菌风险 |
| 特异度 | TN/(TN+FP) | 阴性预测值 | 假阳性导致实验资源浪费 |
2.6 计算实战:Python 实现
我在日常工作里最喜欢用 sklearn 的 metrics 模块,几行代码就能拿到所有指标。但为了让你明白底层逻辑,我写一段纯 Python 的计算示例,不依赖库:
def compute_metrics(y_true, y_pred):
"""y_true和y_pred都是列表,0=负类,1=正类"""
tp = sum(1 for t,p in zip(y_true,y_pred) if t==1 and p==1)
tn = sum(1 for t,p in zip(y_true,y_pred) if t==0 and p==0)
fp = sum(1 for t,p in zip(y_true,y_pred) if t==0 and p==1)
fn = sum(1 for t,p in zip(y_true,y_pred) if t==1 and p==0)
accuracy = (tp+tn)/(tp+tn+fp+fn) if tp+tn+fp+fn else 0.0
precision = tp/(tp+fp) if tp+fp else 0.0
recall = tp/(tp+fn) if tp+fn else 0.0
specificity = tn/(tn+fp) if tn+fp else 0.0
return {
"TP":tp, "TN":tn, "FP":fp, "FN":fn,
"accuracy":accuracy,
"precision":precision,
"recall":recall,
"specificity":specificity
}
# 举个栗子(模拟宏基因组预测)
y_true = [1,0,1,1,0,0,1,0]
y_pred = [1,0,0,1,0,1,1,0]
result = compute_metrics(y_true, y_pred)
print(result)
输出大概长这样:
{'TP':3, 'TN':3, 'FP':1, 'FN':1,
'accuracy':0.75,
'precision':0.75,
'recall':0.75,
'specificity':0.75}
这个例子很理想化,刚好所有指标都是0.75。但实际宏基因组数据中,这四个值往往差异巨大——我见过召回率0.95但精确率只有0.1的情况,那基本就是“宁肯错杀一千”的策略。具体怎么取舍?得看业务场景。比如病原体筛查,宁可假阳性也不想漏检,那就优先保召回率;药物靶点筛选,假阴性成本高但假阳性可能导致后续实验大坑,两者都需要平衡。
好了,这四个常用指标你应该能分清楚了吧?我个人觉得,它们是后续学习AUC的基石——因为AUC实际上就是在不同阈值上综合了召回率和特异度的能力。接下来我们就把这些指标用起来,看看它们和ROC曲线之间的关系。不过这部分留到后面章节,不急。