本文转自:http://liouwei20051000285.blog.163.com/blog/static/252367420091016104545884/
今天我们来介绍一下ROC(Receiver operating characteristics)国内复旦张文彤老师在《SPSS统计分析基础教材》中将其翻译成“受试者工作特征”,也有按字面意思译成“接受者操作特征曲线”。到底选择哪一个大家自便吧。ROC曲线是有TP(True positive rate)、FP(Flase positive rate)构成的,以TP作为Y轴,FP作为X轴。
对于一个离散型分类器(discrete classifier),每一个分类器仅仅对测试集生成一组(fp,tp)点。这个结果对应着ROC空间上的一个点,例如上图中的A、B、C几个点。那么如何让它们产生一个曲线就成了大家最关心的问题。
有一种方法通过对每一个样本集中的样本依次排序进入队列,来到一个样本就计算一次(fp,tp)值,直到样本集中样本全部进入为止。这样我们就得到了一个与样本数量相同的(fp,tp)数组了。然后我们通过这个二维数组我们就可以在ROC空间上做出一个ROC曲线了。具体的算法大家可以参见《An introduction to ROC anslysis》Tom Fawcett, 2005。这篇论文中对ROC曲面进行了很详细的讲解。
这样我们就可以得到一个如上图所示的ROC曲线。我们可以看到上图中有很多条ROC曲线,但是到底哪一条ROC曲线代表对应的分类器的分类效果?这也是一个值得探讨的问题。我们可以看到ROC曲线下面覆盖了一定的面积,不同的曲线覆盖的大小不同,于是一个通俗的想法就是比较它们覆盖面积的不同来判断分类器的效果。当然这个通俗的想法也是有其缘由的,因为对于在ROC空间中的点来说,分类器的分类效果越好它所对应的TP值就越高,FP越低,那么这个对应的点就越靠近西北方向(及左上角)。那么对于一个分类效果比较好的分类器来说,它的ROC曲面必然靠近西北方向,当然它所覆盖的面积就会比其它分类效果较差的分类器要大了。学界称这个面积为Area under the ROC curve(AUC)。
说了这么多,如果需要仔细了解ROC的原理请大家参考上文提到的那篇论文。现在我将weka中得到ROC曲面的方法,以及通过SPSS绘制一个ROC曲面的方法以源码的形式介绍给大家:
package com.csdn;
imp
imp
imp
imp
imp
imp
imp
imp
imp
imp
imp
imp
imp
/*
* Date: 2009.4.6
* by: Wang Yi
* Email: wangyi19840906@yahoo.com.cn
* QQ: 270135367
*
*/
public class SimpleROC {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
/*
* 1.读入数据集
*/
Instances da
new BufferedReader(
new FileReader("C:\Program Files\Weka-3-6\da
da
/*
* 2.训练分类器并用十字交叉验证法来获得Evaluation对象
* 注意这里的方法与我们在上几节中使用的验证法是不同。
*/
Classifier cl = new NaiveBayes();
Evaluation ev
ev
/*
* 3.生成用于得到ROC曲面和AUC值的Instances对象
* 顺带打印了一些其它信息,用于在SPSS中生成ROC曲面
* 如果我们查看weka源码就会知道这个Instances对象包含了很多分类的结果信息
* 例如:FMeasure、Recall、Precision、True Positive Rate、
* False Positive Rate等等。我们可以用这些信息绘制各种曲面。
*/
ThresholdCurve tc = new ThresholdCurve();
//classIndex is the index of the class to consider as "positive"
int classIndex = 0;
Instances result = tc.getCurve(ev
System.out.println("The area under the ROC curve: " + ev
/*
* 在这里我们通过结果信息Instances对象得到包含TP、FP的两个数组
* 这两个数组用于在SPSS中通过线图绘制ROC曲面
*/
int tpIndex = result.attribute(ThresholdCurve.TP_RATE_NAME).index();
int fpIndex = result.attribute(ThresholdCurve.FP_RATE_NAME).index();
double [] tpRate = result.attributeToDoubleArray(tpIndex);
double [] fpRate = result.attributeToDoubleArray(fpIndex);
Util.writeArray(tpRate, fpRate, "d:\roc.txt");
/*
* 4.使用结果信息instances对象来显示ROC曲面
*/
ThresholdVisualizePanel vmc = new ThresholdVisualizePanel();
//这个获得AUC的方式与上面的不同,其实得到的都是一个共同的结果
vmc.setROCString("(Area under ROC = " +
Utils.doubleToString(tc.getROCArea(result), 4) + ")");
vmc.setName(result.relationName());
PlotData2D tempd = new PlotData2D(result);
tempd.setPlotName(result.relationName());
tempd.addInstanceNumberAttribute();
vmc.addPlot(tempd);
// 显示曲面
String plotName = vmc.getName();
final javax.swing.JFrame jf =
new javax.swing.JFrame("Weka Classifier Visualize: "+plotName);
jf.setSize(500,400);
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(vmc, BorderLayout.CENTER);
jf.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent e) {
jf.dispose();
}
});
jf.setVisible(true);
}
}
在代码的第三部分,有一个result 的结果信息对象被建立,这个对象里面有很多分类器分类后产生的结果,如代码中解释的那样,它们包括,TP Rate, FP Rate, Recall, FMeasure等等。在这里我将这个Instances的arff头罗列出来供大家参见。
@relation ThresholdCurve
@attribute 'True Positives' numeric
@attribute 'False Negatives' numeric
@attribute 'False Positives' numeric
@attribute 'True Negatives' numeric
@attribute 'False Positive Rate' numeric
@attribute 'True Positive Rate' numeric
@attribute Precision numeric
@attribute Recall numeric
@attribute Fallout numeric
@attribute FMeasure numeric
@attribute Threshold numeric
由于在weka中得到的ROC曲线图不够清晰而且无法导出,因此我通过SPSS绘制了ROC曲线。我们是通过result这个对象得到TP Rate和 FP Rate数组,然后借助SPSS的线图功能得到ROC曲线图的。线图效果图如下:
PS:最近发现我的源代码下载后无法正常工作,大家可以把"imp
Util.writeArray(tpRate, fpRate, "d:\roc.txt");";就OK了。这个函数仅仅是为了打印出tpRate,fpRate两个指标而已。
PS2:现在我这个实例仅仅是对类别标签 classIndex=0来做的,也就是说,我做的这个ROC曲面是相对于第一个类别的。对于二类别问题,它们两个类别做处理的ROC曲面是一样的,这个没有什么问题,但是如果是多类问题,要比较某个分类器的在某个类别上的分类效果,大家要将classIndex指定到需要测试的类别标签上。