9-3 决策阈值与ROC-AUC评估
📌 一、 课程导入(10分钟)
在上节课《9-2 分类模型评估》中,我们回答了课后拓展思考题:在医疗诊断或风险预警等场景中,“漏诊(FN)”的后果远比“误诊(FP)”更严重,我们更追求高的 Recall(召回率)。
抛出“固定门槛”矛盾: 逻辑回归模型输出的是样本属于正类的概率值 $P(Y=1\vert{}X)$。默认情况下,系统采用 $0.5$ 作为判定临界点(即概率 $\ge 0.5$ 判为正类)。
- 思考:在宿管晚归预警系统中,一个学生晚上未归概率是
0.35,默认模型会判定为“正常(0)”。但在安全管理中,这已经存在很高风险,必须预警! - 问题:如果概率门槛固定死在
0.5,我们该如何控制模型,让它变“严”或者变“宽”?
核心结论: 我们需要通过手动调整 决策阈值(Decision Threshold) 来打破默认限制,使模型精准契合不同场景的业务需求。
- 👨🏫 教师活动:在黑板上画出 0 到 1 的概率轴,标记默认 0.5 刻度,提问:“在安检防爆或风险预警时,概率达到多少就应该拦截?”
- 🧑🎓 学生活动:思考并回答:应该把标准降低(如 0.2 或 0.3),宁可误报也不能漏过危险品。
通过业务场景的实际需求引发认知冲突,帮助学生理解:模型预测不是一成不变的,人为设定门槛(阈值)是控制模型偏向的关键手法。
📖 二、 解决问题过程(一):决策阈值调整与 ROC-AUC 全局评估(25分钟)
1. 决策阈值(Decision Threshold)的权衡
- 降低阈值(如 $T = 0.3$):
- 门槛放宽,更容易被判为正类 $\rightarrow$ Recall(查全率)提升 ↑,但 Precision(查准率)下降 ↓。
- 应用场景:宿管晚归预警、医疗重病筛查(宁可错杀/误报,绝不漏报)。
- 提高阈值(如 $T = 0.7$):
- 门槛变高,要求极有把握才判为正类 $\rightarrow$ Precision(查准率)提升 ↑,但 Recall(查全率)下降 ↓。
- 应用场景:垃圾短信拦截、升学风险高精准干预(追求极高准确度,避免误伤正常学生)。
2. ROC 曲线与 AUC 指标
单一阈值只能评估某个具体门槛下的表现。要评估模型在 所有可能阈值下的综合能力,需要使用 ROC 曲线 与 AUC 得分。
- ROC 曲线的两大核心轴:
- 纵轴:TPR(True Positive Rate,真阳性率) $= \frac{\text{TP}}{\text{TP} + \text{FN}}$ (即 Recall,越接近 1 越好)。
- 横轴:FPR(False Positive Rate,假阳性率) $= \frac{\text{FP}}{\text{FP} + \text{TN}}$ (负样本中被误报的比例,越接近 0 越好)。
- AUC(Area Under Curve):
- ROC 曲线下方的面积大小,数值范围在 $0.5 \sim 1.0$ 之间。
- $\text{AUC} = 0.5$:等同于瞎猜(对角线);$\text{AUC} \ge 0.85$:优质模型,分类区分度极强。
- 👨🏫 教师活动:画出以 FPR 为横轴、TPR 为纵轴的坐标系,对比展示两条不同的 ROC 曲线,解释“越靠近左上方(TPR 高且 FPR 低),模型性能越优”。
- 🧑🎓 学生活动:对比不同模型的 AUC 面积大小,讨论并归纳为什么 AUC 能不受具体阈值选择的影响而客观评价模型。
将阈值调控的单点动态过程升华为全局评估视角(ROC-AUC),培养学生多维度评价算法性能的综合能力。
💻 三、 解决问题过程(二):自定义阈值截断与 ROC-AUC 代码实战(25分钟)
在 Python 中,通过 model.predict_proba() 获取概率数组,再配合布尔掩码快速实现自定义阈值拦截;使用 sklearn.metrics 绘制 ROC 曲线。
- 👨🏫 教师活动:在 Jupyter Notebook 中演示
predict_proba(X)[:, 1]的截取逻辑,引导学生观察将阈值改为0.7后 Console 输出中 Precision 与 Recall 的反向变化。 - 🧑🎓 学生活动:同步敲击代码,修改
custom_threshold参数值,验证阈值高低与评估指标之间的变动规律。
通过代码实战突破 predict_proba 概率拦截与类型转换语法,直观体会改参带来的指标变化,达到学以致用的目的。
✍️ 四、 解决问题过程(三):课堂练习与巩固(20分钟)
📝 五、 课堂小结(5 分钟)
flowchart LR
root["📊 9-3 阈值调优与 ROC-AUC"]
subgraph C1["⚖️ 决策阈值 Threshold"]
direction TB
A1["降低阈值 (T < 0.5):提高 Recall (防漏报)"]
A2["提高阈值 (T > 0.5):提高 Precision (防误报)"]
end
subgraph C2["📈 ROC-AUC 全局评估"]
direction TB
B1["纵轴 TPR:真阳性率 (Recall)"]
B2["横轴 FPR:假阳性率 (误报率)"]
B3["AUC 面积:越接近 1 模型性能越优"]
end
subgraph C3["💻 代码 API"]
direction TB
C1_node["predict_proba 函数取概率"]
C2_node["(probs >= T).astype(int) 逻辑拦截"]
C3_node["roc_curve / roc_auc_score 函数"]
end
root --> C1
root --> C2
root --> C3
style root fill:#4b6cb7,stroke:#253b6e,color:#fff,stroke-width:2px,rx:8px,ry:8px
style C1 fill:#e3f2fd,stroke:#2196f3,stroke-width:1px
style C2 fill:#fff3e0,stroke:#ff9800,stroke-width:1px
style C3 fill:#e8f5e9,stroke:#4caf50,stroke-width:1px