2. ROC曲线绘制:TPR与FPR的定义、绘制步骤、对角线含义
在风险计量中,AUC(Area Under the Curve)是衡量模型区分正负样本能力的核心指标。而AUC的几何基础正是ROC曲线。本章将严格定义真正率(TPR)与假正率(FPR),拆解ROC曲线的绘制步骤,并解释对角线的统计含义。
2.1 混淆矩阵与TPR、FPR的定义
在二分类风险模型中,预测结果与真实标签组合形成混淆矩阵。下表展示了四种基本计数:
| 真实正例 (P) | 真实负例 (N) | |
|---|---|---|
| 预测正例 | TP (真正例) | FP (假正例) |
| 预测负例 | FN (假负例) | TN (真负例) |
基于混淆矩阵,定义两个核心比率:
- 真正率(TPR) = TP / (TP + FN) = TP / P
含义:模型正确识别出的正例占所有真实正例的比例。在风控中,TPR代表“坏客户被正确捕获”的比率,也称为召回率(Recall)或灵敏度(Sensitivity)。 - 假正率(FPR) = FP / (FP + TN) = FP / N
含义:模型错误地将负例预测为正例的比例。在风控中,FPR代表“好客户被误判为坏客户”的比率,也称为误警率(Fall-out)。
记忆技巧:TPR关注“抓对了多少坏人”;FPR关注“误伤了多少好人”。一个好的风控模型应追求高TPR同时保持低FPR。
2.2 ROC曲线绘制步骤
ROC曲线通过遍历所有可能的分类阈值,计算每个阈值下的(TPR, FPR)坐标点,并将这些点连接成曲线。具体步骤如下:
- 获取预测概率:模型对每个样本输出一个介于0到1之间的风险评分或概率值。
- 排序:将所有样本按预测概率从高到低排序。
- 遍历阈值:从最高概率到最低概率,依次将每个样本的预测概率作为分类阈值。
- 计算混淆矩阵:对于每个阈值,将预测概率≥阈值的样本判为正例,<阈值的判为负例,统计TP、FP、FN、TN。
- 计算坐标点:根据混淆矩阵计算TPR和FPR,得到点(FPR, TPR)。
- 绘制曲线:将所有点按FPR从小到大连接,形成ROC曲线。
关键细节:当阈值为0时,所有样本均被判为正例,此时TPR=1,FPR=1,对应右上角(1,1)点;当阈值为1时,所有样本均被判为负例,此时TPR=0,FPR=0,对应左下角(0,0)点。因此ROC曲线始终从(0,0)出发,终止于(1,1)。
下表总结了阈值变化对TPR和FPR的影响趋势:
| 阈值变化方向 | 预测正例数量 | TPR变化 | FPR变化 |
|---|---|---|---|
| 阈值降低 | 增加 | 上升(捕获更多正例) | 上升(误伤更多负例) |
| 阈值升高 | 减少 | 下降(漏掉部分正例) | 下降(误伤减少) |
2.3 对角线含义与随机模型
ROC曲线图中的对角线(从(0,0)到(1,1)的直线)代表一个完全随机猜测模型的性能。其数学表达式为:TPR = FPR。
对角线的统计含义:
- 无区分能力:无论阈值如何调整,模型正确识别正例的概率与错误识别负例的概率始终相等,说明模型没有学到任何有效信息。
- 基准线:任何有效模型的ROC曲线都应位于对角线上方。曲线越靠近左上角(0,1)点,模型性能越好。
- AUC=0.5:对角线下方面积为0.5,这是随机模型的AUC值。AUC>0.5表示模型优于随机猜测。
风控实战警示:在样本极度不平衡(如坏客户占比<1%)时,即使模型表现很差,也可能因为大量TN的存在而使得AUC看起来不低。此时必须结合提升度(Lift)或KS统计量进行综合评估,不能仅依赖AUC。
2.4 ROC曲线与对角线对比示意图
下图展示了三条典型ROC曲线及其与对角线的位置关系:
2.5 代码实现:从预测概率到ROC曲线
以下Python代码展示了如何手动计算TPR和FPR并绘制ROC曲线:
import numpy as np
import matplotlib.pyplot as plt
def calculate_roc(y_true, y_score):
"""
手动计算ROC曲线的TPR和FPR
参数:
y_true: 真实标签 (0或1)
y_score: 预测概率 (0到1)
返回:
fpr_list, tpr_list: 各阈值下的假正率和真正率
"""
# 按预测概率降序排序
sorted_indices = np.argsort(y_score)[::-1]
y_true_sorted = y_true[sorted_indices]
# 统计正负样本总数
P = np.sum(y_true_sorted == 1)
N = np.sum(y_true_sorted == 0)
# 初始化
tpr_list = [0.0]
fpr_list = [0.0]
tp = 0
fp = 0
# 遍历每个样本作为阈值
for i in range(len(y_true_sorted)):
if y_true_sorted[i] == 1:
tp += 1
else:
fp += 1
tpr = tp / P
fpr = fp / N
tpr_list.append(tpr)
fpr_list.append(fpr)
return fpr_list, tpr_list
# 示例数据
y_true = np.array([1, 0, 1, 0, 1, 0, 0, 1, 0, 0])
y_score = np.array([0.9, 0.8, 0.7, 0.6, 0.55, 0.4, 0.3, 0.2, 0.1, 0.05])
fpr, tpr = calculate_roc(y_true, y_score)
# 绘制ROC曲线
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, 'b-', linewidth=2, label='ROC曲线')
plt.plot([0, 1], [0, 1], 'k--', linewidth=1, label='随机模型')
plt.xlabel('假正率 (FPR)')
plt.ylabel('真正率 (TPR)')
plt.title('ROC曲线')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
工程建议:在实际项目中,推荐直接使用
sklearn.metrics.roc_curve 和 sklearn.metrics.roc_auc_score 函数,它们经过高度优化且处理了边界情况。手动实现仅用于理解原理。
2.6 本章小结
- TPR = TP / P,衡量模型捕获正例的能力;FPR = FP / N,衡量模型误伤负例的程度。
- ROC曲线通过遍历所有阈值,绘制(FPR, TPR)轨迹,反映模型在不同阈值下的综合表现。
- 对角线(TPR = FPR)代表随机模型,是评估模型有效性的基准线。
- ROC曲线越靠近左上角,模型区分能力越强;AUC即为曲线下方面积,量化了这一性能。