2013年5月1日星期三

ROC曲线简介

一个典型的ROC曲线如下图所示:



基本概念



     一个分类模型(分类器)是一个将一个实例映射到一个特定类的过程。分类器的结果可以是一个实数(连续输出),这些分类器中类的边界必须通过一个阈值检测,举例来说,通过血压来检测一个人是否有高血压,或者它可以作为一个离散的标签表明的类。 让我们来考虑一个两类预测问题(双分类器),其结果要么是真(p)要么是假(n)。在双分类器中有4类可能的输出。如果输出的预测是p而真实的结果也是p,那么这就叫做真阳性(TP);然而如果真实的结果是n,则这就叫做假阳性(FP)。相反的来说,一个真阴性发生在预测结果和实际结果都为n的时候,而假阴性是当预测输出是n而实际值是p的时候。
为了得到一个现实世界中的恰当的例子,考虑一个检测一个人是否得一种病的测试。一个假阳性就是一个人被测试是有这种病的,但实际却没有的情况。一个假阴性就是一个人被测试是健康的,但实际却是得病的情况。 其多种情况可由以下矩阵表示:
真实值
pn全部
预测
输出
p'
阳性

阳性
P'
n'
阴性

阴性
N'
全部PN

ROC空间


要生成一个ROC曲线,只需要真阳性率(TPR)和假阳性率(FPR)。TPR决定了一个分类器或者一个诊断测试在所有阳性样本中能正确区分的阳性案例的性能。而FPR是决定了在所有阴性的样本中有多少假阳性的判断。 ROC空间将FPR和TPR定义为xy轴,这样就描述了真阳性(获利)和假阳性(成本)之间的博弈。而TPR就可以定义为灵敏度,而FPR就定义为(1-特异度),因此ROC曲线有时候也叫做"灵敏度和1-特异度"图像。每一个预测结果在ROC空间中以一个点代表。
最好的可能预测方式是一个在左上角的点,在ROC空间坐标轴(0,1)点,这个代表着100%灵敏(没有假阴性)和100%特异(没有假阳性)。而(0,1)点被称为完美分类器。一个完全随机预测会得到一条从左下到右上对角线(也叫无识别率线)上的一个点。一个最直观的随机预测的作决定的例子就是抛硬币。
这条斜线将ROC空间划分为两个区域,在这条线的以上的点代表了一个好的分类结果,而在这条线以下的点代表了差的分类结果。
让我们来看四个100个阳性和100个阴性的案例:
ABCC'
TP=63FP=2891
FN=37TN=72109
100100200
TP=77FP=77154
FN=23TN=2346
100100200
TP=24FP=88112
FN=76TN=1288
100100200
TP=76FP=1288
FN=24TN=88112
100100200
TPR = 0.63TPR = 0.77TPR = 0.24TPR = 0.76
FPR = 0.28FPR = 0.77FPR = 0.88FPR = 0.12
ACC = 0.68ACC = 0.50ACC = 0.18ACC = 0.82
图中给出了上面4个结果的ROC空间分布。A方式的结果是A,B,C中最好的一个。B的结果是一种随机猜测线(那条斜线),在表中我们可以看到B的精确度是50%。然而当将C作一个镜像后,C的结果甚至要比A还要好。这个作镜像的方法就是简单的不管C预测了什么,就做其预测的反面。离左上角越近的预测,其结果越好。或者说,离随机猜测线越远,则预测的结果越好,如果其点是在右下方的,那么只需作一个镜像即可。

ROC空间中的线



离散分类器,如决策树,产生的是离散的数值或者一个双标签。应用到实例中,这样的分类器最后只会在ROC空间产生单一的点。而一些其他的分类器,如朴素贝叶斯分类器,逻辑回归或者人工神经网络,产生的是实例属于某一类的可能性,对于这些方法,一个阈值就决定了ROC空间中点的位置。举例来说,如果可能值低于或者等于0.8这个阈值就将其认为是阳性的类,而其他的值被认为是阴性类。这样就可以通过画每一个阈值的ROC点来生成一个生成一条曲线。MedCalc是较好的ROC曲线分析软件。

2013年4月30日星期二

简单分析新浪微博上自己的粉丝数与互粉好友粉丝数的关系

    以前好像在某个日志看到过有关于社交网络的有趣数据,其中一个就是你的好友的好友数量普遍都比你自己的好友数量多。这两天正好在看可视化方面的书籍,突然想到可以画个简单的图来看看是不是这样。下面就是我的具体做法了。
    我选择的社交网站是新浪微博,这个选择完全是因为我个人的原因。由于上学期做过相关的爬虫,对新浪微博的数据获取有一定的经验。我选取的实验样本就是我的互粉好友,共计68个人。
    对这68个好友,我分别获取到他们的粉丝数量和他们所有互粉好友粉丝的数量,然后计算出互粉好友粉丝数量的平均值,这样就得到了作图需要的数据源。具体结果如下图,

    通过R语言就可以使用这个数据生成图形了,我做出的第一个图是每个人的两个数据对比柱状图。图片如下:
    从该图可以明显看出,几乎所有的用户的好友粉丝数都多于自己的粉丝数。上面19个人的数据中,只有2个人不符合这一说法。
    为了从总体上刻画出这一问题,我又作了第二张图。


    这张图可以清楚地反应出用户的粉丝数主要几种在50到250这个区间,而用户好友粉丝数的平均值主要分布在250到450这个区间。
    下面展示最后一张图。这是一张二者的密度图。
    


    从这张图可以得到如第二图同样的结果,同样非常直观。
    今天的工作到这里就结束了,这里画图只用了R中最基础的画图函数。等以后学习了高级的画图包之后再看看能不能重画这些图。

    具体代码的链接如下:https://github.com/doumengyu/FansCountComparison

【转载】 ggplot2绘图入门系列之五:时间序列(完)

ggplot2包也能对时间序列数据绘图,但在处理上需要有些注意的地方。下面我们以上证指数为例进行作图,首先利用quantmod包从yahoo数据源获取从1997年以来的数据,存于变量SSEC中,抽取收盘数字,然后分别提取时间数据和指数数值,绘图结果如下图。
library(quantmod)
library(ggplot2)
getSymbols('^SSEC',src='yahoo',from = '1997-01-01')
close <- (Cl(SSEC))
time <- index(close)
value <- as.vector(close)
p <- ggplot(data.frame(time,value),aes(time,value))
p + geom_line()

我们希望能够在图中加入一些其它的说明元素,以丰富视图中所包含的信息。这些信息包括用不同的颜色区块来表示“江核心”和“胡核心”的执政时期,以及对中国证券市场的若干大事件进行标注。最后的代码和结果如下。
yrng <- range(value)
xrng <- range(time)
data <- data.frame(start=as.Date(c('1997-01-01','2003-01-01')),end=as.Date(c('2002-12-30','2012-01-20')),core=c('jiang','hu'))
timepoint <- as.Date(c('1999-07-02','2001-07-26','2005-04-29','2008-01-10','2010-03-31'))
events <- c('证券法实施','国有股减持','股权分置改革','次贷危机爆发','融资融券试点')
data2 <- data.frame(timepoint,events,stock=value[time %in% timepoint])
p + geom_line()
  + geom_rect(aes(NULL,NULL,xmin = start, xmax = end, fill = core),ymin = yrng[1],ymax=yrng[2],data = data)
  + scale_fill_manual(values = alpha(c('blue','red'),0.2))
  + geom_text(aes(timepoint, stock, label = events),data = data2,vjust = -2,size = 5)
  + geom_point(aes(timepoint, stock),data = data2,size = 5,colour = alpha('red',0.5))

【转载】 ggplot2绘图入门系列之四:再说散点图

前文中已初步介绍了散点图的绘制方法,本文介绍一些细节方面的参数设置。

1 色彩和形状的控制
数据特征不仅可以用坐标来表示,也可以用不同的色彩或形状来表示。仍以mpg数据集为例,所用到的变量有cty(城市中行驶距离),hwy(高速路行驶距离),displ(排量大小),year(生产年份)
library(ggplot2)
p <- ggplot(mpg, aes(cty, hwy))
p1 <- p + geom_point(aes(colour = factor(year),shape = factor(year), size = displ), alpha = 0.6, position = 'jitter')
print(p1)
我们将1999年生产车型用红色圆形表示,2008年用兰色三角形表示,排量用图形的大小表示,并且设置了透明度和jitter以避免样本点之间的重叠。可观察到2008年生产的大排量车型较多,从而油耗较高,单位油耗行驶距离较短。

2 坐标的控制
上图右上角数据点较为稀疏,这种情况下可用对数变换。为了演示ggplot2对图形坐标的控制,我们对X轴和Y轴均进行对数变换,然后对X轴的坐标显示加以限制,只显示X轴数据的均值,以及一倍标准差的坐标。

cty.mean=with(mpg,mean(cty))
cty.sd=with(mpg,sd(cty))
p1 + scale_x_continuous(trans='log',breaks=c(cty.mean-cty.sd,cty.mean,cty.mean+cty.sd), labels=c("high", "mean", "low")) + scale_y_continuous(trans='log')


3 文字说明
利用geom_text函数可添加文字说明以增强图形的可读性

p <- ggplot(mtcars, aes(x=wt, y=mpg,colour=factor(cyl),label=rownames(mtcars))) 
p + geom_text(hjust=0,vjust=-1,alpha=0.8)+ geom_point(size=3,aes(shape=factor(cyl)))


4 矩阵散点图
ggplot2包中也提供了矩阵散点图函数

plotmatrix(USArrests)+geom_smooth()

【转载】ggplot2绘图入门系列之三:位置调整与条形图

位置调整(Position adjustments)是针对同一图层内元素的位置进行微调的方法。它包括五种设置,分别是stack、dodge、fill、identity、jitter。

我们用条形图来展示其用法,仍使用mpg数据集,其中用到的变量是class,即生产汽车的类型,以及year生产年份。下面的条形图是将各类型的汽车数量进行汇集,并以年份作为分组变量。我们首先载入扩展包,然后用频数表对数据进行大致的了解,最后绘制了四种条形图。
library(ggplot2)
with(mpg,table(class,year))
p <- ggplot(data=mpg,aes(x=class,fill=factor(year)))
p + geom_bar(position='dodge')
p + geom_bar(position='stack')
p + geom_bar(position='fill')
p + geom_bar(position='identity',alpha=0.3)
 





可以看到dodge方式是将不同年份的数据并列放置;stack方式是将不同年份数据堆叠放置,这也是geom_bar的默认处理方式;fill方式和stack类似,但Y轴不再是计数,而是以百分比显示;identity方式是不做任何改变直接显示出来,所以需要设置透明度才能看得清楚。

geom_bar是绘制条状几何对象,所以也可以用不经汇集的原始数据进行绘图。下面我们用2001到2010年间的美国GDP增长率举个例子。

y=c(1.1,1.8,2.5,3.6,3.1,2.7,1.9,-0.1,-3.5,3.0)
x=2001:2010
data=data.frame(x,y)
p=ggplot(data,aes(x,y,fill=y))
p+geom_bar(stat="identity")+ 
    geom_abline(intercept = 0, slope = 0,size=1,colour='gray')+
    geom_text(aes(label=y),hjust=0.5, vjust=-0.5 )+
    scale_y_continuous(limits=c(-3.8,4.2))+
    labs(x='年份', y='GDP增长率%')+
    opts(title = "美国GDP增长率")


【转载】ggplot2绘图入门系列之二:图层控制与直方图

前文所述,ggplot2使用图层将各种图形元素逐步添加组合,从而形成最终结果。第一层必须是原始数据层,其中data参数控制数据来源,注意数据形式只能是数据框格式。aes参数控制了对哪些变量进行图形映射,以及映射方式,aes是Aesthetic的缩写。

下面我们来绘制一个直方图作为示例。数据集仍采取mpg,对hwy变量绘制直方图。首先加载了扩展包,然后用ggplot函数建立了第一层,hwy数据映射到X轴上;使用+号增加了第二层,即直方图对象层。此时p被视为一种层对象,使用summary函数可得到关于它的更多信息,print(p)命令即可进行绘图。

library(ggplot2)
p <- ggplot(data = mpg,aes(x = hwy))
p <- p + geom_histogram()
summary(p)
data: manufacturer, model, displ, year, cyl, trans,
  drv, cty, hwy, fl, class [234x11]
mapping:  x = hwy
faceting: facet_grid(. ~ ., FALSE)
-----------------------------------
geom_histogram:
stat_bin:
position_stack: (width = NULL, height = NULL)

上面的信息告诉我们,p对象含有两层,第一层数据层描述了变量和映射方式,第二层是直方图对象(geom_histogram),geom表示几何对象,它是ggplot中重要的图层控制对象,因为它负责图形渲染的类型。geom_histogram是图形渲染类型的一种,其它类型可参见官网

每个geom对象都需要有数据输入,数据可以从第一层中自动读取,也可以在aes参数中直接设置。而且每个geom还默认搭配某种统计变换(stat),geom_histogram的默认统计变换是stat_bin。它负责对数据进行分组计数。

下面我们尝试两种更为复杂的直方图,首先将数据按照year这个变量划分为两组,用不同的颜色绘制直方图,而且用频率而非计数来刻画Y轴,并添加密度曲线。
p <- ggplot(mpg,aes(hwy))
p + geom_histogram(position = 'identity',
    alpha=0.5,
    aes(y = ..density..,
    fill = factor(year))+
    stat_density(geom = 'line',
    position = 'identity',
    aes(colour = factor(year)))
如果想将两个直方图分开绘制,也可以使用facet_grid参数,结果如下图所示。

另:在win系统中用ggplot2绘制直方图,其底部有难看的缺口。但在linux系统中正常,不知原因何在,望知情人士不吝赐教。

【转载】ggplot2绘图入门系列之一:导论


1 什么是ggplot2
ggplot2是用于绘图的R语言扩展包,其理念根植于《Grammar of Graphics》一书。它将绘图视为一种映射,即从数学空间映射到图形元素空间。例如将不同的数值映射到不同的色彩或透明度。该绘图包的特点在于并不去定义具体的图形(如直方图,散点图),而是定义各种底层组件(如线条、方块)来合成复杂的图形,这使它能以非常简洁的函数构建各类图形,而且默认条件下的绘图品质就能达到出版要求。

2 与lattice包的比较
ggplot2和lattice都属于高级的格点绘图包,初学R语言的朋友可能会在二者选择上有所疑惑。从各自特点上来看,lattice入门较容易,作图速度较快,图形函数种类较多,比如它可以进行三维绘图,而ggplot2就不能。ggplot2需要一段时间的学习,但当你跨过这个门槛之后,就能体会到它的简洁和优雅,而且ggplot2可以通过底层组件构造前所未有的图形,你所受到的限制只是你的想象力。


建议两种绘图包都可以研究一下。如果时间紧张,需要在一两天之内为论文做一张图,那么推荐用lattice,如果时间充裕,推荐学习ggplot2。

3 基本概念

  • 图层(Layer):如果你用过photoshop,那么对于图层一定不会陌生。一个图层好比是一张玻璃纸,包含有各种图形元素,你可以分别建立图层然后叠放在一起,组合成图形的最终效果。图层可以允许用户一步步的构建图形,方便单独对图层进行修改、增加统计量、甚至改动数据。
  • 标度(Scale):标度是一种函数,它控制了数学空间到图形元素空间的映射。一组连续数据可以映射到X轴坐标,也可以映射到一组连续的渐变色彩。一组分类数据可以映射成为不同的形状,也可以映射成为不同的大小。
  • 坐标系统(Coordinate):坐标系统控制了图形的坐标轴并影响所有图形元素,最常用的是直角坐标轴,坐标轴可以进行变换以满足不同的需要,如对数坐标。其它可选的还有极坐标轴。
  • 位面(Facet):很多时候需要将数据按某种方法分组,分别进行绘图。位面就是控制分组绘图的方法和排列形式。

4 一个例子
下面用ggplot2包内带的汽车测试数据(mpg)来举个例子,用到的三个变量分别是发动机容量(displ)、高速公路上的每加仑行驶里数(hwy)、汽缸数目(cyl)。首先加载ggplot2包,然后用ggplot定义第一层即数据来源。其中aes参数非常关键,它将displ映射到X轴,将hwy映射到Y轴,将cyl变为分类数据后映射为不同的颜色。然后使用+号添加了两个新的图层,第二层是加上了散点,第三层是加上了loess平滑曲线。
library(ggplot2)
p <- ggplot(data=mpg,aes(x=displ,y=hwy,colour=factor(cyl)))
p + geom_point() + geom_smooth()
上图是对几种不同汽缸的数据分别平滑,如果需要对整体数据进行平滑,可将colour参数设置在散点图层内而非第一层,这样第三层的平滑图形就不会受到colour参数的影响。
p <- ggplot(mpg,aes(x=displ,y=hwy))
p + geom_point(aes(colour=factor(cyl))) + geom_smooth()
其它资源:
http://had.co.nz/ggplot2/ (官方主站)
http://xccds1977.blogspot.com/2011/12/qplot.html (快速入门)
ggplot2 Elegant Graphics for Data Analysis (下载