Receiver Operating Characteristic Area Under the Curve (ROC and AUC).
如何向别人解释 ROC AUC 对评价机器学习算法的意义:
一个样本集,一半正样本,一半为负样本。如果一个机器学习算法将全部样本均预测为正(或者负),也即是一种 trivial 的方式,它的准确率即可达到 50%,fifty fifty 的正确率就像抛一枚硬币一样。引入 ROC AUC 的评估方式(evaluation)可以实现了分类性能对样本类别比例的稳定性;
1. TPR FPR
![ROC曲线与AUC区域的理解与实践 ROC曲线与AUC区域的理解与实践](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwybHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEx6SXdNVFF3TXpBeU1UUXhOek0xT0RFeQ%3D%3D.jpg?w=700&webp=1)
- Precision(精确率):
P=TPTP+FP - Recall(召回率):
R=TPTP+FN -
Fscore=21/P+1/R
-
- TPR (True Positive Rate):
tpr=TPTP+FN=TPP - FPR (False Positive Rate):
FPR=FPFP+TN=FPN
def TPR(y_true, y_pred):
return ((y_true==1)*(y_pred==1)).sum()/(y_true==1).sum()
def FPR(y_true, y_pred):
return ((y_true==0)*(y_pred==1)).sum()/(y_true==0).sum()
2. plot ROC curve
对于一个特定的分类器与测试数据集,显然只能得到一个分类结果,即一组TPR与FPR值,而要画出一个曲线,我们便需要一系列的FPR与TPR值。我们来看 Wikipedia对其的定义,
In signal detection theory, a receiver operating characteristic (ROC), or simply ROC curve, is a graphical plot which illustrates the performance of a binary classifier system as its discrimination threshold is varied.
如何理解这里的 discrimination threshold呢?其实我们忽略了分类器的一个重要功能是“概率输出”,即表示分类器某个样本以多大的概率属于正样本或负样本。对于0,1二分类问题,一些分类器得到的其实不是简单的0和1,如神经网络,得到诸如0.5, 0.8这样的分类结果。这时,如果我们人为指定一个阈值(threshold),比如0.4,那么小于0.4的为0类,大于等于0.4的则为1类,则可得一个分类结果(该分类结果再跟真实的结果相结合,可进而计算TPR与FPR)。
阈值不同,可以得到不同的结果,但是由于分类器所决定的统计图始终是不变的。这时候就需要一个独立于阈值,只与分类器有关的评价指标,来衡量特定分类器的好坏。
假如我们已经得到了所有样本的概率输出(属于正样本的概率),现在的问题是如何改变“discrimination threshold”呢?我们根据每个训练样本属于正样本的概率值从大到小进行排序。下图为某一示例,共20个训练样本,”Class”一列表示每个样本真正的标签(p为正样本,n表示负样本),”Score”表示每个测试样本属于正样本的概率。
![ROC曲线与AUC区域的理解与实践 ROC曲线与AUC区域的理解与实践](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwybHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEx6SXdNVFl3TVRFeE1qQTBNak0zTVRFeQ%3D%3D.jpg?w=700&webp=1)
接下来,我们从高到低,依次将”Score”值作为阈值(threshold)。每次选取一个不同的 threshold,我们就可以得到一组FPR和TPR,这样一来我们共得到20组FPR与TPR的值,即得ROC curve:
def main():
y_true = np.array([1, 1, 0, 1, 1, 1, 0, 0, 1, 0,
1, 0, 1, 0, 0, 0, 1, 0, 1, 0])
y_hat = np.array([.9, .8, .7, .6, .55, .54, .53, .52, .51, .505,
.4, .39, .38, .37, .36, .35, .34, .33, .30, .1])
threshs = sorted(y_hat, reverse=True)
tprs, fprs = [], []
for thresh in threshs:
y_pred = np.where(y_hat < thresh, 0, 1)
# np.where, numpy版的三目运算符
tprs.append(TPR(y_true, y_pred))
fprs.append(FPR(y_true, y_pred))
plt.plot(fprs, tprs, 'k--', lw=2)
plt.scatter(fprs, tprs, c='k', marker='x', s=50)
plt.plot(np.arange(-.05, 1.05, .01), np.arange(-.05, 1.05, .01), '--', color='lightgray')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.xlim([0-.05, 1+.05])
plt.ylim([0-.05, 1+.05])
plt.show()
if __name__ == '__main__':
main()
![ROC曲线与AUC区域的理解与实践 ROC曲线与AUC区域的理解与实践](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwybHRaeTVpYkc5bkxtTnpaRzR1Ym1WMEx6SXdNVFl3TVRFeE1qSXdNalU1TkRVMg%3D%3D.jpg?w=700&webp=1)
当threshold取值越多,ROC曲线越光滑。
3. AUC 值的计算
AUC(Area Under Curve)被定义为ROC曲线下的面积,显然这个面积的数值不会大于1,整个ROC空间为坐标轴上的
首先把所有样本按照score排序,依次用rank表示,最大score的样本,rank=n (n=M+N),其次为 n-1。
这里不妨给出一份AUC的计算代码:
def AUC(y_true, scores):
M = (y_true==1).sum() # M:正样本个数
N = (y_true==0).sum() # N:负样本个数
I = np.argsort(scores)
rank = 0
for i in range(1, 1+len(I)):
if y_true[I[-i]] == 1:
rank += len(I)-i+1
return (rank-M*(M+1))/(M*N)
4. 为什么使用ROC Curve
既然已经存在那么多评价标准,为什么还要使用ROC和AUC呢?因为ROC曲线有个很好的特性:当训练集中的正负样本的分布(np.bincount(y_train))变化的时候,ROC曲线能够保持不变,也即ROC不受训练集类别分布的影响。因为在实际的训练集中经常会出现类不平衡(class imbalance)现象,即正样本占90%,或者相反(此时如果一个将所有样本当预测为正样本的分类器,也能得到90%的准确率,显然这样毫无意义)。