从底层数学原理手撕分类模型评估指标 (Accuracy, F1, ROC, AUC)

32 阅读3分钟

从底层数学原理手撕分类模型评估指标 (Accuracy, F1, ROC, AUC)

标签: #机器学习 #算法面试 #推荐系统 #数学原理


👨‍💻 前言:为什么准确率高达 99% 的模型却被老板骂了?

在算法岗位的面试中,或者在推荐系统的实际工作中,你是否遇到过这样的灵魂拷问:

“我的模型 Accuracy 只有 90%,你的有 99%,为什么我的模型上线效果比你更好?”

“请手写一个计算 AUC 的函数,不能调包。”

“为什么 F1-score 用的是调和平均数,而不是算术平均数?”

很多同学在学习评估指标时,往往只背了公式(TP/FP 分不清),却忽略了背后的业务逻辑数学本质

今天,我将结合最近的一场深度技术探讨,带大家从混淆矩阵出发,一路推导到 AUC 的代码实现,彻底搞懂这些指标背后的玄机。


一、 万物之源:混淆矩阵 (Confusion Matrix)

所有的指标都逃不开这四个基础概念。不要死记硬背,请用**“新冠检测”**的例子来理解:

  • TP (True Positive)真阳性。确实有病,模型也说有病。(抓对了)
  • FN (False Negative)假阴性。确实有病,模型说没病。(漏报,后果很严重)
  • FP (False Positive)假阳性。其实没病,模型非说有病。(误报,吓死人)
  • TN (True Negative)真阴性。其实没病,模型也说没病。(没事了)

二、 基础指标的博弈:Precision vs Recall

1. 准确率 (Accuracy) 的陷阱

Accuracy=TP+TN总样本Accuracy = \frac{TP + TN}{总样本}

致命弱点: 当样本极度不平衡时(例如 100 个样本里只有 1 个正样本),模型只要无脑预测“全为负”,准确率就有 99%。但这个模型是废的。

2. 精确率 (Precision) 与 召回率 (Recall)

  • Precision (查准率) :预测为正的样本里,多少是真的? -> 关注“别误杀” (比如垃圾邮件拦截)。
  • Recall (查全率) :真实为正的样本里,找出来多少? -> 关注“别漏掉” (比如地震预警、癌症筛查)。

大师心得: 这两者是一对矛盾体。你想查得全(Recall 高),往往就会误报多(Precision 低)。


三、 进阶指标:F1 Score 的数学之美

为了平衡 P 和 R,我们引入了 F1 Score。但面试官常问:为什么是调和平均数?

F1=2×P×RP+RF1 = 2 \times \frac{P \times R}{P + R}

我们看下刚才探讨中的手写笔记推导

数学推导

调和平均数的本质是**“倒数的算术平均数的倒数”**。

1F1=1P+1R2\frac{1}{F1} = \frac{\frac{1}{P} + \frac{1}{R}}{2}

化简后即可得到 F1 的标准公式。

核心物理意义

“短板效应” :调和平均数对较小值非常敏感。

  • 如果 P=1,R=0P=1, R=0,算术平均数是 0.5(看起来还行),但 F1 Score 是 0。
  • 结论: 只有当 Precision 和 Recall 都很高时,F1 才会高。这强迫模型不能偏科。

四、 推荐/排序系统的王牌:AUC (Area Under Curve)

在点击率预测(CTR)或风控场景下,我们更关心排序能力。这时候,ROC 和 AUC 就登场了。

1. ROC 曲线怎么看?

  • 横轴 (FPR) :误报率(越小越好)。
  • 纵轴 (TPR) :召回率(越大越好)。
  • 绘制原理:移动分类阈值(Threshold),把所有可能的 (FPR, TPR) 点连成线。

2. AUC 的核心定义(高频考点)

面试题: “请用一句话解释 AUC 的概率意义。”

标准答案:

从所有样本中随机抽取一个正样本和一个负样本,模型预测正样本得分 > 负样本得分的概率。

  • AUC = 0.5:等同于瞎猜。
  • AUC = 1.0:完美排序,所有正样本都在负样本前面。

五、 硬核实战:手撕 AUC 计算代码

面试中最怕的一句话来了:“不要用 sklearn.metrics.roc_auc_score,请你自己写一个 AUC 计算函数,复杂度要低。”

如果你去算积分面积,代码会很复杂。我们需要利用 AUC 的排序统计公式

AUC=i正样本rankiM(M+1)2M×NAUC = \frac{\sum_{i \in 正样本} rank_i - \frac{M(M+1)}{2}}{M \times N}

公式原理大白话

  1. 全员 PK:AUC 本质是看正样本赢了多少次负样本。
  2. 利用 Rank:一个样本的 Rank(排名)其实代表了有多少样本排在它后面。
  3. 扣除内耗rank\sum rank_{正} 包含了“正 > 负”和“正 > 正”。减去 M(M+1)2\frac{M(M+1)}{2} 就是把“正 > 正”这部分自己人的比较扣掉,剩下的就是“正 > 负”的次数。

Python 代码实现 (可以直接背诵版)

Python

def fast_auc(labels, preds):
    """
    labels: 真实标签列表 [0, 1, 1, 0, ...]
    preds: 预测概率列表 [0.1, 0.9, 0.8, ...]
    """
    # 1. 核心步骤:按预测分数从小到大排序
    # zip打包后,key=lambda x:x[0] 表示按预测值排序
    f = list(zip(preds, labels))
    # 提取排序后的标签序列,这是计算Rank的基础
    rank = [value2 for value1, value2 in sorted(f, key=lambda x:x[0])]
    
    # 2. 统计所有正样本的 Rank (注意:Rank从1开始,所以索引+1)
    ranklist = [i + 1 for i in range(len(rank)) if rank[i] == 1]
    
    # 3. 统计正负样本个数 M 和 N
    posNum = sum(labels)
    negNum = len(labels) - posNum
    
    # 4. 套用公式计算
    # 分子:正样本Rank和 - 正样本内部排序的常数项
    numerator = sum(ranklist) - posNum * (posNum + 1) / 2
    # 分母:正负样本的总组合数
    denominator = posNum * negNum
    
    # 防止除以0的异常情况
    if denominator == 0:
        return 0.0
        
    return numerator / denominator

代码解析:

  • 使用了 sorted,时间复杂度为 O(NlogN)O(N \log N),远快于两层循环的 O(N2)O(N^2)
  • 完全基于统计学公式,避免了复杂的微积分逻辑。

六、 总结与建议

  • 样本均衡看 Accuracy。
  • 关注“误报” (垃圾邮件)看 Precision。
  • 关注“漏报” (医疗/安防)看 Recall。
  • 需要综合指标看 F1 Score(记得它是调和平均)。
  • 推荐/广告/风控排序,不管样本偏不偏,无脑上 AUC
  • 面试手撕代码,请牢记上面的 Rank 公式法。