推荐系统之ROC和AUC详解

2023-05-16

前言

这个绝对是重量级内容了,也是很基础的东西。对于模型来讲, 不同的阈值会有不同的泛化能力, 这时候,如果想比较两个模型的泛化能力, 这个阈值的高低也会受到影响, 所以就需要能够综合考虑着所有阈值下的模型的泛化性能,这样还可以使得模型适应与不同的任务, 那这时候应该怎么评估模型呢? ROC曲线是常用的工具。

在这里和我们前面说过的PR曲线是类似的(mAP),但是在之前的PR 曲线中横纵坐标是查准率和查全率。但是在这里就换成了真正例率(TPR)和假正例率(FPR),这两个也是根据混淆矩阵来计算的,这里看不懂的可以去看看我之前的文章目标检测指标mAP详解。

1、PR曲线和ROC曲线的区别

首先来说一下ROC曲线的定义,先看一下下面的图:

在这里插入图片描述

 真正例率TPR: 这个就是查全率, 真实情况为正的样本中,模型预测为正的比例,公式\frac{1}{1+ 2 }

 正例率FPR: 这个就是真实情况为负的样本中,模型预测为正的比例, 公式\frac{3}{3+4}

这两个就是ROC曲线的横纵坐标了,那么为什么大家在推荐系统中不会使用PR曲线了呢?

这是因为在推荐系统中很容易发生正负样本不均衡的情况,相比PR曲线,ROC曲线有个特点就是,当正负样本的分布发生变化时, ROC曲线的形状能够基本保持不变, 而P-R曲线的形状一般会发生剧烈的变化, 这个特点让ROC曲线能够尽量降低不同测试集带来的干扰, 更加客观的衡量模型本身的性能。很多实际问题中, 正负样本的数量往往不均衡,比如计算广告中,正样本往往是负样本的1/10000, 若选择不同的测试集,P-R曲线的变化就会非常大, 而ROC曲线则能够更加稳定的反映模型的好坏,这也是为啥ROC曲线应用广泛的原因。当然, 选择PR曲线还是ROC曲线还是应该因实际问题而定, 如果希望更多的看到模型在特定数据集上的表现, PR曲线则能够更加直观的反映性能。在反欺诈场景下,假设正常用户为正类(设占比 99.9%),欺诈用户为负类(设占比 0.1%)。如果使用准确率评估,则将所有用户预测为正类即可获得 99.9%的准确率。这并不是一个很好的预测结果,因为欺诈用户全部未能找出。使用AUC评估,则此时FPR=1,TPR=1,对应的AUC=0.5 。AUC成功的指出了这并不是一个很好的预测结果。

2、AUC物理意义以及计算

AUC代表的肯定就是ROC曲线下的面积,但是它的真实代表含义是随机给定一个正样本和一个负样本,正样本预测 分数大于负样本预测分数的概率。AUC越大, 表示模型预测样本为正样本的概率比模型预测样本为负样本的概率大, 书上说的样本预测排序质量的度量,与排序误差有紧密关系。如:AUC=0.8表示:给定一个正样本和一个负样本,在 80% 的情况下,模型对正样本预测为正类的概率大于对负样本预测为正类的概率。(将正样本排在负样本前面的概率)。所以在正负样本不均衡的地方AUC仍然适用。

其中AUC的好处还有如下所示:

  • 使用精确率,召回率和F1值进行模型评估时需要设定阈值,阈值的大小会影响模型的泛化能力,使用AUC评估模型性能时可以不设定阈值
  • AUC计算主要与排序有关,它对排序敏感,而对预测分数没那么敏感(排序结果更重要,不管预测值是多少,只要正例的预测概率都大于负例就行,将预测概率同乘以1.2,AUC值不变)
  • 在一定条件下,RankBoost算法优化的全局函数就是AUC,可以使用RankBoost算法优化AUC的近似值或对AUC进行局部优化。(paper);xgboost提供了直接优化AUC的功能,目标函数设置为:objective = ‘rank:pairwise’。
  • 当正负样本的分布发生变化时,P-R曲线的形状一般会发生比较剧烈的变化,而ROC曲线的形状能够基本保持不变。这使得ROC曲线能够尽量降低不同测试集带来的干扰,更加客观地衡量模型本身的性能。

代码:

def auc(y_label, y_pred):
	
	n = len(y_label)
	pos_pred = [y_pred[i] for i in range(n) if y_label[i] == 1]
	neg_pred = [y_pred[i] for i in range(n) if y_label[i] == 0]
	n_pos = len(pos_pred)   # 正样本的个数
	n_neg = len(neg_pred)   # 负样本的个数
	auc = 0
	# 对任一一对pair, 正 > 负的pair个数除以pair对的总数就是auc
	for i in range(n_pos):
		for j in range(n_neg):
			if pos_pred[i] > neg_pred[j]:
				auc += 1
			elif pos_pred[i] == neg_pred[j]:
				auc += 0.5
	
	return auc / (n_pos * n_neg)



def auc(y_label, y_pred):
	# 先按照预测概率从小到大排序,然后找正样本所在的索引值
	n_pos = sum(y_label)
	n_neg = len(y_label) - n_pos
	label_pred = list(zip(y_label, y_pred))
	label_pred.sort(key=lambda x: x[1])   # 按照概率从小到大排序
	
	pos_label_index_acc = 0
	for i, (label, pred) in enumerate(label_pred):
		if label == 1:
			pos_label_index_acc += i
	
	acc_1_m = n_pos * (n_pos - 1) / 2
	return (pos_label_index_acc - acc_1_m) / (n_pos * n_neg)

参考:翻滚的小强

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

推荐系统之ROC和AUC详解 的相关文章

随机推荐