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)坐标点,并将这些点连接成曲线。具体步骤如下:

  1. 获取预测概率:模型对每个样本输出一个介于0到1之间的风险评分或概率值。
  2. 排序:将所有样本按预测概率从高到低排序。
  3. 遍历阈值:从最高概率到最低概率,依次将每个样本的预测概率作为分类阈值。
  4. 计算混淆矩阵:对于每个阈值,将预测概率≥阈值的样本判为正例,<阈值的判为负例,统计TP、FP、FN、TN。
  5. 计算坐标点:根据混淆矩阵计算TPR和FPR,得到点(FPR, TPR)。
  6. 绘制曲线:将所有点按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曲线及其与对角线的位置关系:

ROC曲线与对角线对比 假正率 (FPR) 真正率 (TPR) 0 1 0 1 随机模型 (AUC=0.5) 优秀模型 (AUC≈0.95) 中等模型 (AUC≈0.75) 理想点 (0,1) 曲线越靠近左上角,模型区分能力越强;对角线代表无区分能力的随机猜测

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即为曲线下方面积,量化了这一性能。