一维数据可视化:核密度估计(Kernel Density Estimates)

对于大量一维数据的可视化,除了使用直方图(Histogram),还有一种更好的方法:核密度估计(Kernel Density Estimates,简称KDE)。

所谓核密度估计,就是采用平滑的峰值函数(“核”)来拟合观察到的数据点,从而对真实的概率分布曲线进行模拟。以下面3个数据点的一维数据集为例:

5, 10, 15  

绘制成直方图是这样的: histo

而使用KDE则是: kde

KDE核函数

理论上,所有平滑的峰值函数均可作为KDE的核函数来使用,只要对归一化后的KDE而言(描绘在图上的是数据点出现的概率值),该函数曲线下方的面积和等于1即可 — 只有一个数据点时,单个波峰下方的面积为1,存在多个数据点时,所有波峰下方的面积之和为1。概而言之,函数曲线需囊括所有可能出现的数据值的情况。常用的核函数有:矩形、Epanechnikov曲线、高斯曲线等。单个数据点0所对应的这些核函数为:

矩形 rect

Epanechnikov曲线 epanechnikov

高斯曲线 gauss

可以看到,这些函数存在共同的特点:

  1. 在数据点处为波峰
  2. 曲线下方面积为1

对于多个数据点的KDE曲线,由于相邻波峰之间会发生波形合成,因此最终所形成的曲线形状与选择的核函数关系并不密切。考虑到函数在波形合成计算上的易用性,一般使用高斯曲线(正态分布曲线)作为KDE的核函数。

带宽

除了核函数,另一个影响KDE的参数是带宽(h)。带宽反映了KDE曲线整体的平坦程度,也即观察到的数据点在KDE曲线形成过程中所占的比重 — 带宽越大,观察到的数据点在最终形成的曲线形状中所占比重越小,KDE整体曲线就越平坦;带宽越小,观察到的数据点在最终形成的曲线形状中所占比重越大,KDE整体曲线就越陡峭。还是以上面3个数据点的一维数据集为例,如果增加带宽,那么生成的KDE曲线就会变平坦: kde-smooth

如果进一步增加带宽,那么KDE曲线在变平坦的同时,还会发生波形合成: kde-more-smooth

相反,如果减少带宽,那么KDE曲线就会变得更加陡峭: kde-less-smooth

从数学上来说,对于数据点Xi,如果带宽为h,那么在Xi处所形成的曲线函数为(其中K为核函数): kde-math

在上面的函数中,K函数内部的h分母用于调整KDE曲线的宽幅,而K函数外部的h分母则用于保证曲线下方的面积符合KDE的规则(KDE曲线下方面积和为1)。

带宽的选择很大程度上取决于主观判断:如果认为真实的概率分布曲线是比较平坦的,那么就选择较大的带宽;相反,如果认为真实的概率分布曲线是比较陡峭的,那么就选择较小的带宽。

大量一维数据的KDE绘制

在选择合适的核函数及带宽后,KDE可以模拟真实的概率分布曲线,并得到平滑而漂亮的结果。仍以直方图(Histogram)文章中近200个点的CPU使用率为例,使用KDE绘制的结果为: kde-draw-result

R中KDE的实现

在R语言中,KDE的绘制是通过density()函数来实现的 — 通过density()函数计算得到KDE模型,然后再使用plot()函数对KDE曲线进行绘制:

x <- c(5, 10, 15)  
d <- density(x)  
plot(d)  

在实现过程中,也可以将这两步合并为一句语句:

plot(density(x))  

出于兼容性上的考虑,R语言中density()函数在计算带宽时,默认采用”nrd0″方法。不过,根据R语言的帮助文档,带宽参数bw应该显式声明为其它更合适的方法,比如”SJ”:

plot(density(x, bw="SJ"))  

对于调整带宽,除了修改bw参数,还可以通过设定adjust参数来进行扩大或缩小:

plot(density(x, bw="SJ", adjust=1.5))  

在上面的例子中,最终使用的带宽将是采用”SJ”方法计算得到的带宽的1.5倍。adjust参数的默认值为1,也即既不扩大、也不缩小。

至于核函数,density()默认采用高斯曲线。可以通过设定kernel参数来更改核函数。比如:

plot(density(x, bw="SJ", kernel="epanechnikov"))  

density()函数接受以下7个核函数选项:

  • gaussian。高斯曲线,默认选项。在数据点处模拟正态分布。
  • epanechnikov。Epanechnikov曲线。
  • rectangular。矩形核函数。
  • triangular。三角形核函数。
  • biweight
  • cosine。余弦曲线。
  • optcosine