一维数据可视化:累积分布函数(Cumulative Distribution Function)

对于一维数据的可视化,直方图(Histogram)与核密度估计(Kernel Density Estimates)可以很好的表示各个数据值的概率分布,但在表示数据累积分布上这两种方法就无能为力了。数据的累积分布,也即小于等于当前数据值的所有数据的概率分布,对于表示数据点在某个区间内出现的概率有很大的帮助。从数学上来说,累积分布函数(Cumulative Distribution Function, 简称CDF)是概率分布函数的积分;而在绘制累积分布函数的时候,由于真实的概率分布函数未知,因此往往定义为直方图分布的积分: cdf-definition

累积分布函数(CDF)的使用

以-4到4之间分布的10000个数据点为例,绘制成直方图与核密度估计是这样的: histo kde

这两张图可以很好的表示-4到4之间任意数据值的概率大小,但是在回答下面几个问题的时候就比较困难了:

  1. 所有大于2的数据点在总数据集中所占比例约有多大?
  2. 所有大于1.3而小于2的数据点在总数据集中所占比例是多少?

在上述例子中,数据集大致遵循正态分布,因此从直方图或核密度估计的结果中推测这两个问题的答案还是可能的;但是对于不规则的概率分布曲线来说,这样做就基本上行不通了。回答上述问题的通用方法是绘制累积分布函数图: cdf-diagram

根据这张累积分布函数图,可以很方便地回答之前的两个问题:

  1. CDF中横轴上的2对应的Y值约为0.98,因此所有大于2的数据点所占比例约为2%。
  2. CDF中横轴上的1.3对应的Y值约为0.75,因此所有介于1.3和2之间的数据点所占比例约为23% (0.98-0.75)。

与直方图、核密度估计相比,累积分布函数存在以下几个特点:

  • 累积分布函数是X轴单调递增函数。
  • 累积分布函数更加平滑,图像中噪音更小。
  • 累积分布函数没有引入带宽等外部概念,因此不会丢失任何数据信息。对于给定的数据集,累积分布函数是唯一的。
  • 累积分布函数一般都经过归一化处理,单调递增且趋近于1。

R中累积分布函数(CDF)的实现

在R中,累积分布函数的绘制是通过ecdf()函数来实现的。对于任何数据分布,累积分布函数都是概率分布函数的积分;因为真实的概率分布函数未知,所以真实的累积分布函数也就无法从数据样本中精确推导出来了。ecdf()函数中的e代表Empirical,意思是根据观察值而来的,也即具体描绘出来的CDF曲线是根据各个数据点的加和而得到的。

以直方图(Histogram)文章中近200个点的CPU使用率数据为例,用R绘制CDF的语句为:

cpu <- scan("cpu_data.txt")  
plot(ecdf(cpu))  

其结果为: r-cdf-result

可以看到,累积分布函数图很好的表示了各个区间内数据分布的概率。美中不足的是,上面的图像中数据点过大,各数据点间也没有进行连接,因此在视觉效果上与“曲线”相差甚远。为了美化累积分布函数图,可以在plot()函数的调用过程中设定参数:

cpu <- scan("cpu_data.txt")  
plot(ecdf(cpu), do.points=FALSE, verticals=TRUE)  

从而得到更加自然的结果: r-cdf-better-result

如果需要用平滑曲线来拟合累积分布函数,从而作出更加漂亮的图的话,可以使用sROC包中的kCDF()函数:

//安装sROC包
install.packages("sROC")  
//加载sROC包
library(sROC)  
plot(kCDF(cpu))  

结果如下: r-cdf-smooth

上图中,中间的黑色加粗曲线是拟合的累积分布函数,而浅灰色的区域则是置信区间。