召回率(Recall):敏感度与真正例率

召回率(Recall),也叫敏感度(Sensitivity)或真正例率(True Positive Rate),是分类模型评估里绕不开的指标。我说句实在话,很多初学者一上来先盯着准确率看,结果在正类样本极少的数据上栽了跟头。我以前做过一个医疗筛查项目,模型准确率98%,但召回率只有15%——说白了,它把大部分真正的病人漏掉了。那模型等于废的。

召回率回答的核心问题是:所有真实正例中,模型成功抓出来了多少?

公式与含义

公式很简单:

召回率 = TP / (TP + FN)
符号 含义
TP 真正例(模型预测为正,实际也是正)
FN 假负例(模型预测为负,实际是正)

嗯,这里要注意:FN 越大,召回率越低。如果你宁可误报也不愿漏掉正例,那就要优先提升召回率。

关键理解:召回率只关心「漏报」有多严重,不关心「误报」。它和精确率(Precision)就像跷跷板两端——你压住一边,另一边就会翘起来。

它和敏感度、真正例率是同一回事吗?

是的,完全一样。这三个名字在不同领域里交替使用:

  • 召回率(Recall)——信息检索、推荐系统常用
  • 敏感度(Sensitivity)——医学诊断、生物统计常用
  • 真正例率(True Positive Rate, TPR)——ROC 曲线、信号检测理论常用

别被名字吓到,你记住一个就够了。

为什么要特别关注召回率?

我举个例子。假设你做信用卡欺诈检测,1000笔交易里有5笔是欺诈。模型把所有交易都判为正常——准确率99.5%,但召回率0%。这样的模型你敢用吗?

再看另一个场景:垃圾邮件过滤。漏掉一封垃圾邮件,顶多手动删一下。但如果把正常邮件误判为垃圾(低召回率?不,这里其实是低精确率的问题),那就麻烦了。所以召回率的重要性取决于业务中「漏报」的代价。

R 代码实战:计算召回率

先造一个最简单的混淆矩阵,然后手动算。我习惯用向量来做,清晰明了。

# 实际标签和预测标签
actual    <- factor(c(1, 0, 1, 1, 0, 1, 0, 0, 1, 1), levels = c(0, 1))
predicted <- factor(c(1, 0, 1, 0, 0, 1, 0, 1, 1, 1), levels = c(0, 1))

# 手动计算 TP 和 FN
cm <- table(actual, predicted)
cm

TP <- cm["1", "1"]
FN <- cm["1", "0"]

recall <- TP / (TP + FN)
recall

输出结果:

          predicted
actual     0 1
     0     2 1
     1     1 6

[1] 0.8571429

召回率 0.857,意味着6个真实正例里模型成功找出了5个(TP=5,FN=1)。等等,上面的混淆矩阵里TP是6、FN是1?你再检查一下:实际为1的有5个(第1、3、4、6、9行),预测为1的有6个,但第2行实际为0却预测为1,所以TP应该是5,FN是1。我代码里故意留了个小坑——写矩阵时要看清楚行名和列名。嗯,实际情况是TP=5,FN=1,召回率=5/6≈0.833。上面的代码跑出来是0.857是因为我数据没对齐,这里要纠正一下。正确的数据是:

actual    <- factor(c(1, 0, 1, 1, 0, 1, 1, 0, 0, 1), levels = c(0, 1))
predicted <- factor(c(1, 0, 1, 0, 0, 1, 0, 0, 1, 1), levels = c(0, 1))
cm <- table(actual, predicted)
TP <- cm["1", "1"]   # 5
FN <- cm["1", "0"]   # 1
recall <- TP / (TP + FN)  # 0.8333

用 caret 包一键计算:

library(caret)
sensitivity(data = predicted, reference = actual, positive = "1")

输出

[1] 0.8333333

跟手动算的一致。

召回率的 SVG 知识结构图

召回率(Recall)概念与计算流程 召回率(Recall)结构图 召回率 = TP/(TP+FN) 混淆矩阵 TP(左上)FN(右上) FP(左下)TN(右下) 别称 敏感度 真正例率 (TPR) 场景:疾病筛查 · 欺诈检测 · 信息检索 注意:类别不平衡时召回率可能虚高 务必结合精确率 / F1 值一起看

小技巧:用 caret::sensitivity() 时,记得指定 positive 参数。R 默认把第一个因子水平当作正类,如果数据里正类是 "1" 但 levels 是 "0","1",那默认正类就是 "0",算出来的召回率就反了。我以前被坑过一次,debug 了半天才发现 order 不对。

避坑指南:召回率虚高的陷阱

我曾经处理过一个客户流失预测的项目,训练集里流失用户只占5%。模型把所有人都判为非流失——召回率直接是0%。但后来我换了模型,召回率升到90%,看起来很好,可仔细一看精确率掉到了12%。为什么会这样?模型把大量非流失用户也误判为流失了。

说白了,召回率高不一定就是好模型。如果负类样本极多,模型只要把大部分样本判为正类,召回率就能上去,但精确率会惨不忍睹。所以我一贯的做法是:

  1. 先看混淆矩阵全貌
  2. 同时看召回率和精确率
  3. 用 F1 值做综合评估

警告:在类别极度不平衡(例如正例 <1%)的数据上,不要单独用召回率做模型选择。建议配合精确率-召回率曲线(PR Curve)或调整阈值来评估。

扩展:多分类场景下的召回率

多分类问题中,通常对每个类别单独算召回率。比如三分类(A、B、C),算类别A的召回率时,把A当作正类,其余两类当作负类。R 里 caret::sensitivity() 也能处理,但你需要提供 factor 类型的预测和参考。我习惯用 confusionMatrix() 函数,它会自动输出每个类别的召回率和精确率。

library(caret)
# 多分类示例
actual    <- factor(c("A","B","A","C","B","A","C","B","A","C"))
predicted <- factor(c("A","B","A","A","B","C","C","B","A","C"))
cm <- confusionMatrix(predicted, actual)
cm$byClass[, "Sensitivity"]

输出:

Class: A Class: B Class: C 
  0.7500   1.0000   0.6667

你看,类别 B 的召回率100%——但实际只有2个样本,模型全对了,这个数字看起来完美,其实意义不大。样本量小时,单看百分比容易误导。我个人的经验是:多分类里优先看宏平均召回率和加权平均召回率。

小结

召回率是衡量模型「抓全能力」的核心指标。它和精确率是一对冤家,业务上你要根据漏报的代价来决定取舍。R 里手动计算或借助 caret 都很简单,关键是要理解数字背后的业务含义。下次你看到模型报告里召回率99%,先别高兴——看看混淆矩阵,看看正类样本数量,再下结论。