3. 混淆矩阵与核心指标:TP/FP/TN/FN、准确率、精确率、召回率、F1-score、特异度
在风控模型阈值调优中,混淆矩阵是评估分类模型性能的基础工具。它通过比较模型预测结果与实际标签,将样本划分为四种基本类型。理解这些核心指标,是后续设定最优告警阈值的数学前提。
3.1 混淆矩阵四象限
对于二分类风控模型(如“好客户” vs “坏客户”),混淆矩阵以实际类别为行、预测类别为列,形成 2×2 矩阵:
| 实际 \ 预测 | 预测为正(告警) | 预测为负(非告警) |
|---|---|---|
| 实际为正(坏客户) | TP(真正例) | FN(假负例) |
| 实际为负(好客户) | FP(假正例) | TN(真负例) |
- TP(True Positive):模型正确告警的坏客户,命中风险。
- FN(False Negative):模型漏过的坏客户,未触发告警,风险最高。
- FP(False Positive):模型误告警的好客户,产生骚扰,增加人工成本。
- TN(True Negative):模型正确放行的好客户,正常通过。
风控视角:FN 代表“漏报”,FP 代表“误报”。在信贷风控中,FN 的成本通常远高于 FP,因为一笔坏账可能抵消数百笔正常交易的利润。
3.2 核心指标定义与计算
基于混淆矩阵的四类计数,可以衍生出多个评估指标。以下为风控场景中最常用的六个指标:
| 指标名称 | 公式 | 风控含义 | 理想方向 |
|---|---|---|---|
| 准确率(Accuracy) | (TP + TN) / (TP + FP + FN + TN) | 整体预测正确的比例 | 越高越好 |
| 精确率(Precision) | TP / (TP + FP) | 告警中真正坏客户的比例(告警准确度) | 越高越好 |
| 召回率(Recall) | TP / (TP + FN) | 坏客户被成功告警的比例(捕获率) | 越高越好 |
| F1-score | 2 × (P × R) / (P + R) | 精确率与召回率的调和平均 | 越高越好 |
| 特异度(Specificity) | TN / (TN + FP) | 好客户被正确放行的比例 | 越高越好 |
| 假正率(FPR) | FP / (FP + TN) = 1 - Specificity | 好客户被误告警的比例 | 越低越好 |
关键理解:准确率在样本不平衡时具有欺骗性。例如,当坏客户仅占 1% 时,模型全部预测为“好客户”也能获得 99% 准确率,但此时召回率为 0%,模型完全失效。风控场景必须关注精确率与召回率的平衡。
3.3 阈值对指标的影响
模型输出的原始分数(如违约概率)需要通过阈值转换为二分类标签。阈值的高低直接影响混淆矩阵的分布:
- 降低阈值:更多样本被判定为正(告警),TP 和 FP 同时增加,FN 减少,TN 减少。召回率上升,精确率下降。
- 提高阈值:更少样本被判定为正(告警),TP 和 FP 同时减少,FN 增加,TN 增加。召回率下降,精确率上升。
阈值调优的核心目标,是在业务容忍度范围内找到最优平衡点。例如,在反欺诈场景中,通常要求召回率 > 95%,同时尽可能控制误报率。
3.4 风控场景指标选择策略
不同风控业务阶段对指标的侧重不同,以下为常见场景的推荐策略:
| 业务场景 | 首要指标 | 次要指标 | 阈值倾向 |
|---|---|---|---|
| 反欺诈实时拦截 | 召回率(Recall) | 精确率(Precision) | 较低阈值,宁可误报不可漏报 |
| 贷前信用审批 | 精确率(Precision) | F1-score | 较高阈值,避免误杀优质客户 |
| 贷中监控预警 | F1-score | 特异度(Specificity) | 平衡阈值,兼顾捕获与误报 |
| 营销响应模型 | 精确率(Precision) | 提升率(Lift) | 较高阈值,精准触达 |
常见误区:不要盲目追求 F1-score 最大化。当业务对 FN 和 FP 的成本权重差异较大时(如欺诈损失是误报成本的 100 倍),应使用加权 Fβ-score 或直接优化业务成本函数,而非标准 F1-score。
3.5 代码示例:计算混淆矩阵与核心指标
以下 Python 代码演示如何基于模型预测概率和阈值,计算混淆矩阵及各项指标:
import numpy as np
from sklearn.metrics import confusion_matrix
# 模拟真实标签与模型预测概率
y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0])
y_prob = np.array([0.85, 0.32, 0.72, 0.91, 0.15, 0.45, 0.60, 0.22, 0.78, 0.08])
# 设定告警阈值
threshold = 0.5
y_pred = (y_prob >= threshold).astype(int)
# 计算混淆矩阵
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
# 计算核心指标
accuracy = (tp + tn) / (tp + fp + fn + tn)
precision = tp / (tp + fp) if (tp + fp) > 0 else 0.0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0.0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0
specificity = tn / (tn + fp) if (tn + fp) > 0 else 0.0
print(f"阈值: {threshold}")
print(f"混淆矩阵 -> TP: {tp}, FP: {fp}, FN: {fn}, TN: {tn}")
print(f"准确率: {accuracy:.4f}")
print(f"精确率: {precision:.4f}")
print(f"召回率: {recall:.4f}")
print(f"F1-score: {f1:.4f}")
print(f"特异度: {specificity:.4f}")
输出示例:
阈值: 0.5
混淆矩阵 -> TP: 4, FP: 1, FN: 1, TN: 4
准确率: 0.8000
精确率: 0.8000
召回率: 0.8000
F1-score: 0.8000
特异度: 0.8000