我有一个经过训练的模型的预测,并且我可以很容易地为数据生成精确召回曲线,因此也可以生成精确召回曲线下面积(AUPRC)。然而,我试图为数据生成95%的置信区间,这方面我很难找到相关资料。我查看了Python的sklearn和R的pROC包(后者确实有一些关于PR的使用,但没有关于AUPRC的),但除了我看不太懂的一些高级学术论文外,我没找到其他内容。
有谁知道好的库或者能帮我找到计算AUPRC的95%置信区间的代码吗?
感谢任何能帮助的人!
回答:
我没看到现有的库能做到这一点,所以我认为你需要自己实现。别担心,这并不难。
我看到三种可能的方法:
- 精确置信区间:将FN/FP解释为从具有精确度或召回率概率的二项分布中采样。使用二项分布的累积分布函数(CDF)来估计精确区间。这是最繁琐的,但即使样本较小也能工作。
- 使用正态近似:基本与之前相同,但使用正态分布的分位数而不是二项分布。如果有100个以上数据点,将生成与(1)几乎相同的结果
- 在1000个随机留出集上重复分类,使用经验精确度和召回率分布来计算置信区间。这是最容易实现的,但需要更多的计算量。
更新: 关于实现的一些提示:
- 精确度是TP/(TP+FP),即对正预测的真实正例的概率
- 召回率是TP/(TP+FN),即对真实正例的正预测的概率。
由于下文将涉及多个概率,我将这两个概率称为PR(精确度或召回率)
为两者获取置信区间的任务是完全相同的。我们基本上是在尝试估计一个伯努利变量的p(如抛硬币正面的几率)。在两种情况下,正面结果的数量(TP)是相同的。唯一的区别是尝试的数量(分母,我将在下文中称为n)。
因此,我们需要将PR的值与观察到的结果的概率联系起来。我们希望找到一些PR值的区间,使得观察到的结果的概率高于某个alpha。使用伯努利分布,我们可以根据正面翻转的几率PR(p)估计观察到结果的概率(P):
P = (n! / (tp! * (n-tp)!)) * (p ** tp) * ((1-p) ** (n-tp))
对其进行累积并反转以求出p就是上面提到的选项1。正如我提到的,这很繁琐(但并非不可能)。
方法2是使用中心极限定理,它基本上说随机变量的总和紧密跟随正态分布。鉴于伯努利分布的方差是p * (1-p)
,而总和的方差与n成反比,我们可以找到总和的标准偏差。现在,以1-alpha的概率,p应该在范围p_hat +/- z_score * standard_deviation_of_sum
内。
最后,实现:
# 我们需要这个来计算z-scorefrom scipy.stats import normdef ci(tp, n, alpha=0.05): """ 估计伯努利p的置信区间 Args: tp: 正面结果的数量,在本例中为TP n: 尝试的数量,精确度为TP+FP,召回率为TP+FN alpha: 置信水平 Returns: Tuple[float, float]: 置信区间的下限和上限 """ p_hat = float(tp) / n z_score = norm.isf(alpha * 0.5) # 两侧,所以每侧alpha/2 variance_of_sum = p_hat * (1-p_hat) / n std = variance_of_sum ** 0.5 return p_hat - z_score * std, p_hat + z_score * std
更新2: 计算AUC的置信区间
sklearn.metrics.auc
需要两个向量,x
和y
值。在这里,精确度和召回率可以互换使用。即,x
是一个估计精确度值的向量,y
是召回率的上限/下限,或者反之——x
是估计的召回率值,y
是精确度的上限或下限。
如果没有sklearn,可以大致按以下方式近似计算:
# 假设data是一个列表,包含(upper_precision, precision, lower precision, upper_recall, recall, lower_recall)auc = 0sort(data, key=lambda x: x[1]) # 按精确度排序last_point = (0, 0) # 最后的x,y值for up, p, lp, ur, r, lr in data: # 用于排序的应该首先 new_point = (p, ur) # 或(r, up)用于上限;(p, lr), (r, lp)用于下限 dx = new_point[0] - last_point[0] y = last_point[1] auc += dx * last_point[1] + dx * (new_point[1] - last_point[1]) * 0.5