返回
Featured image of post 重新理解面试必备的AUC

重新理解面试必备的AUC

之前的理解还是太肤浅

AUC物理意义

ROC曲线下所围成的面积

  • ROC 曲线是以 真正例率(True Positive Rate, TPR) 为纵轴,假正例率(False Positive Rate, FPR) 为横轴绘制的曲线。
  • AUC 是 ROC 曲线下的面积:
    • AUC = 1:模型完美分类,完全区分正负样本。
    • AUC = 0.5:模型没有分类能力,相当于随机猜测。
    • AUC < 0.5:模型性能比随机猜测还差(可能需要检查模型或数据)。

模型对正样本的预测概率高于负样本的概率

AUC 的物理意义可以理解为:随机选择一个正样本和一个负样本,模型对正样本的预测概率高于负样本的概率。AUC 的值范围在 0 到 1 之间,越接近 1 表示模型性能越好。

  1. 假设有N个正样本和M个负样本
  2. 从中随机抽取一个正样本和一个负样本
  3. 如果模型对正样本的预测值大于负样本,就记为一次正确排序
  4. AUC就等于所有可能的正负样本对中,正确排序的比例

这种解读揭示了AUC的本质 - 它实际上在评估模型的排序能力,而不是分类准确率。这也是为什么AUC特别适合推荐系统、搜索引擎等需要对物品进行排序的场景。

AUC计算代码

方法一:基于排序和分组计算

这里注意一个是itertools.groupby的计算 整个函数的时间复杂度由排序操作主导,为 O(nlogn)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import itertools

def my_auc(labels, preds):
    # 计算正负样本数量
    n_pos = sum(labels)
    n_neg = len(labels) - sum(labels)
    # 将标签和预测分数组合成元组列表,并按预测分数排序
    lst = sorted(zip(labels, preds), key=lambda x: x[1])
    # 初始化 AUC 累加值和累计负样本数量
    sum_auc, sum_neg = 0, 0
    # 按预测分数分组遍历
    for _, pairs in itertools.groupby(lst, key=lambda x: x[1]):
        # 初始化当前组的正样本数量和负样本数量
        cnt_pos = 0
        cnt_neg = 0
        # 遍历当前组的每个样本
        for label, pred in pairs:
            cnt_pos += int(label)
            cnt_neg += int(not label)
        # 计算当前组对 AUC 的贡献
        sum_auc += cnt_pos * sum_neg + cnt_pos * cnt_neg / 2
        # 更新累计负样本数量
        sum_neg += cnt_neg
    # 计算最终的 AUC 值
    auc = sum_auc / (n_pos * n_neg)
    # 返回计算得到的 AUC 值
    return auc

# 示例数据
labels = [1, 0, 1, 1, 1, 1, 0, 0, 1]
preds = [0.1, 0.4, 0.9, 0.4, 0.4, 0.5, 0.1, 0.8, 0.2]
# 调用函数计算 AUC
result = my_auc(labels, preds)
# 打印计算结果
print(result)

方法二:在前者的基础上分箱

  • 整个函数的时间复杂度是 O(n+m​),其中 n 是样本数量,m​ 是分箱的数量。
  • 当样本数量 n 远远大于分箱数量 m​ 时,时间复杂度近似为 O(n)
  • 当分箱数量 m​ 远远大于样本数量 n 时,时间复杂度近似为 O(m​)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def my_auc(labels, preds, n_bins=100000):
    # 初始化正负样本的分箱计数列表,每个元素代表一个分箱,初始值都为 0
    neg_his = [0] * n_bins
    pos_his = [0] * n_bins
    # 初始化正负样本的总数为 0
    n_pos = sum(labels)
    n_neg = len(labels) - sum(labels)

    # 遍历每个样本,统计各分箱中的正、负样本数量
    for i in range(len(labels)):
        # 将预测分数乘以分箱数量并取整,得到该样本所在的分箱索引
        idx = int(preds[i] * n_bins)
        # 如果当前样本的真实标签为 0,说明是负样本
        if labels[i] == 0:
            # 对应分箱的负样本计数加 1
            neg_his[idx] += 1
        else:
            # 对应分箱的正样本计数加 1
            pos_his[idx] += 1

    # 计算正样本和负样本的所有可能组合数
    n_pair = n_neg * n_pos
    # 初始化当前分箱之前的所有负样本数量的累加值为 0
    sum_neg = 0
    # 初始化满足正样本预测分数大于负样本预测分数的组合数的累加值为 0
    sum_auc = 0

    # 遍历每个分箱,计算 AUC 值
    for i in range(n_bins):
        # 计算当前分箱对 AUC 的贡献并累加到 sum_auc 中
        # sum_neg * pos_his[i] 
        # 表示当前分箱中的正样本与之前所有分箱中的负样本的正确排序组合数
        # pos_his[i] * neg_his[i] * 0.5 
        # 表示当前分箱内正样本和负样本由于预测分数相同(在同一分箱)
        # 假设一半的组合是正确排序的
        sum_auc += (pos_his[i] * sum_neg + pos_his[i] * neg_his[i] * 0.5)
        # 更新当前分箱之前的所有负样本数量的累加值
        sum_neg += neg_his[i]

    # 返回最终计算得到的 AUC 值
    return sum_auc / n_pair

# 示例数据,真实标签列表
labels = [1, 0, 1, 1, 1, 1, 0, 0, 1]
# 示例数据,对应的预测分数列表
preds = [0.1, 0.4, 0.9, 0.4, 0.4, 0.5, 0.1, 0.8, 0.2]
# 调用自定义函数计算 AUC 值
result = my_auc(labels, preds)
# 打印计算得到的 AUC 值
print(result)

AUC的排序性

AUC 的核心是:随机选择一个正样本和一个负样本,模型对正样本的预测值高于负样本的概率。因此,AUC 强调的是模型将正样本排在负样本前面的能力,而不是具体的预测值大小。

与 Accuracy 和 Precision 的区别

  • Accuracy 和 Precision 是基于分类阈值的指标,需要确定一个阈值来判断样本是正类(1)还是负类(0)。不同的阈值会直接影响这些指标的值。
  • AUC 不需要设置阈值,它综合考虑了所有可能的阈值,因此更关注模型的整体排序能力。

AUC 应用场景

AUC 特别适合排序业务,比如推荐系统、广告点击率预测等。在这些场景中,模型的目标不是绝对分类,而是将用户更可能点击的广告或更感兴趣的商品排在前面


AUC的采样不敏感性

均匀采样时AUC不变

  • 假设模型对某个正样本的预测值为 score1
  • 在真实数据中,预测值高于 score1 的负样本和低于 score1 的负样本比例是固定的(比如 30% 高于,70% 低于)。
  • 在均匀采样中,由于采样比例与真实分布一致,预测值高于 score1 的负样本和低于 score1 的负样本比例仍然是 30% 和 70%。
  • 因此,AUC 的值不会受到影响。

不均匀采样时AUC会变

  • 非均匀采样是指正负样本的采样比例与真实分布不一致。例如,负样本可能更倾向于热门商品,而不是随机采样。
  • 假设模型对某个正样本的预测值为 score1
  • 在真实数据中,预测值高于 score1 的负样本和低于 score1 的负样本比例是固定的(比如 30% 高于,70% 低于)。
  • 在非均匀采样中,由于负样本主要来自热门商品,预测值高于 score1 的负样本比例可能会发生变化(比如下降到 20%),此时AUC会上升。
  • 因此,AUC 的值会因为采样偏差而受到影响。

GAUC

GAUC实际是计算每个用户的auc,然后加权平均,最后得到group auc,这样就能减少不同用户间的排序结果不太好比较这一影响。

GAUC 的公式

GAUC 的公式如下:

$$text{GAUC} = \frac{\sum_{(u,p)} W(u,p) \cdot \text{AUC}(u,p)}{\sum_{(u,p)} W(u,p)} $$

其中:

  • $u$:表示用户(或其他分组维度)。
  • $p$:表示某个用户的数据(通常是该用户的点击行为数据)。
  • $\text{AUC}(u,p)$:针对用户 $u$ 计算的 AUC。
  • $W(u,p)$:用户 $u$ 的权重,通常可以设置为该用户的 曝光次数(view)点击次数(click)

为什么要使用 GAUC?

在推荐系统中,不同用户的行为数据分布差异较大。例如:

  • 某些用户点击率高,正样本较多。
  • 某些用户点击率低,负样本较多。

如果直接使用全局 AUC,可能会因为不同用户的数据分布不一致而导致排序结果不可比。GAUC 通过为每个用户单独计算 AUC,然后进行加权平均,能够更好地评估模型在不同用户上的排序性能。

AUC 的计算步骤

  1. 按用户分组:将数据按照用户划分,每个用户的数据单独处理。
  2. 过滤无效用户:过滤掉以下两种情况:
    • 用户的所有样本都是正样本(全是点击)
    • 用户的所有样本都是负样本(全无点击)
    • 这些用户无法计算 AUC,因此需要被排除
  3. 计算每个用户的 AUC:针对每个有效用户,分别计算其 AUC。
  4. 加权平均:将每个用户的 AUC 乘以对应的权重,然后对所有用户的加权 AUC 求和,最后除以总权重。

AUC 和 GAUC 变化不一致的情况

AUC 上涨(或不变),GAUC 下跌(或不变)

点赞狂魔

  • 现象:少量用户疯狂点赞,导致正样本数量大幅增加。
  • 对 AUC 的影响:全局 AUC 可能上涨或不变,因为正样本增加会提高整体的排序准确性。
  • 对 GAUC 的影响:对于用户维度的 AUC 来说,点赞狂魔的行为并未改善每个用户的排序效果,因此 GAUC 可能下跌或不变。

新用户兴趣差异过大

  • 现象:来了一批新用户,其兴趣与原有用户群体差异过大,导致模型无法准确打分。
  • 对 AUC 的影响:全局 AUC 可能变化不大,因为新用户的样本在整体数据中占比较小。
  • 对 GAUC 的影响:对于新用户来说,模型无法准确排序,导致其 AUC 值较低,从而拉低整体的 GAUC。

AUC 下跌(或不变),GAUC 上涨(或不变)

优化了长尾用户,牺牲了头部用户

  • 现象:模型优化了长尾用户(低频用户、新用户)的个性化推荐,但牺牲了头部用户(高频用户)的全局排序效果。
  • 对 AUC 的影响:全局 AUC 可能下跌或不变,因为头部用户的排序效果被削弱。
  • 对 GAUC 的影响:长尾用户的排序效果提升,其 AUC 值增加,从而拉高整体的 GAUC。

个性化推荐增强

  • 现象:模型不再盲目推送热门内容,而是更关注用户的个性化信号,提升了组内排序质量。
  • 对 AUC 的影响:全局 AUC 可能下跌或不变,因为热门内容的排序效果被削弱。
  • 对 GAUC 的影响:每个用户组内的排序效果提升,其 AUC 值增加,从而拉高整体的 GAUC。

AUC 可能小于 0.5 吗?

通常,随机猜测的模型 AUC 为 0.5。如果模型的性能比随机猜测还差,就会出现 AUC 小于 0.5 的情况。以下是可能导致 AUC 小于 0.5 的原因:

样本标签错误

  • 现象:数据集中正样本和负样本的标签可能被错误标记,例如正样本被标记为负样本,负样本被标记为正样本。
  • 影响:模型学习到的规律与真实规律完全相反,导致 AUC 小于 0.5。
  • 解决方法:检查并修正样本标签的准确性。

样本数据不平衡

  • 现象:正负样本比例极度不平衡,例如正样本占比极少,负样本占比极高。
  • 影响:模型可能会偏向多数类(负样本),导致对少数类(正样本)的预测效果极差,甚至出现 AUC 小于 0.5 的情况。
  • 解决方法:对样本进行平衡处理,例如欠采样、过采样或使用加权损失函数。

模型选择不合理

  • 现象:所选模型无法学习到有效的特征与标签之间的关系。
  • 影响:模型的预测结果与真实标签的关系混乱,导致 AUC 小于 0.5。
  • 解决方法:尝试更复杂的模型或更适合数据的模型,例如从线性模型切换到树模型或神经网络。

模型过拟合或欠拟合

过拟合

  • 现象:模型在训练集上表现很好,但在测试集上泛化能力差。
  • 影响:模型对测试集数据的预测结果可能完全错误,导致 AUC 小于 0.5。
  • 解决方法:添加正则化、减少模型复杂度、增加训练数据等。

欠拟合

  • 现象:模型未能充分学习到数据中的规律。
  • 影响:模型的预测结果与真实标签的关系不明确,可能导致 AUC 小于 0.5。
  • 解决方法:增加模型复杂度、添加更多特征、调整超参数等。

AUC 为 1 的原因

AUC 为 1 表示模型能够完美地将正样本和负样本区分开。然而,在实际场景中,AUC 为 1 通常是异常现象,可能由以下原因导致:

数据标注错误

  • 现象:所有正样本和负样本在特征上存在明显的区分边界。
  • 原因:可能是数据标注出现了系统性错误,例如:
    • 所有正样本的特征值都集中在某一范围内,而所有负样本的特征值集中在另一范围内。
    • 标注规则过于简单或错误,导致样本类别与特征之间存在完全可区分的规律。
  • 影响:模型能够轻易地将两类样本完全分开,从而 AUC 为 1。
  • 解决方法:检查数据标注的合理性,确保标注规则符合实际情况。

数据泄露

  • 现象:训练数据和测试数据之间存在不该有的信息泄露。
  • 原因:例如:
    • 测试数据中的某些样本或其相关信息被包含在训练数据中。
    • 特征中包含了与标签高度相关的信息(例如直接将标签信息作为特征)。
  • 影响:模型在测试时能够“记住”某些样本的标签信息,从而达到完美预测,AUC 为 1。
  • 解决方法:严格区分训练数据和测试数据,确保测试数据的信息未在训练过程中泄露。

GAUC 作为细粒度指标,为什么有些场景仍然使用 AUC?

GAUC并不稳定。若用户行为稀疏(如新用户或低频场景),组内样本量不足以计算GAUC,会出现较大波动,可能导致指标不可靠。此时AUC的全局视角更稳健。


AUC和F1SCORE个应用场景

  • 若业务明确要求高精确率(如垃圾邮件分类)或高召回率(如癌症筛查),优先使用F1-score调整模型
  • 若业务需动态调整阈值(如风险评分),优先使用AUC
© 2023 - 2025 壹壹贰捌· 0Days
共书写了265.7k字·共 93篇文章 京ICP备2023035941号-1