核密度估计(KDE)原理及实现

参数估计指样本数据来自一个具有明确概率密度函数的总体,而在非参数估计中,样本数据的概率分布未知,这时,为了对样本数据进行建模,需要估计样本数据的概率密度函数,核密度估计即是其中一种方式。

引言

统计学中,核密度估计,即Kernel Density Estimation,用以基于有限的样本推断总体数据的分布,因此,核密度估计的结果即为样本的概率密度函数估计,根据该估计的概率密度函数,我们就可以得到数据分布的一些性质,如数据的聚集区域。

从直方图开始

直方图由 Karl Pearson 提出,用以表示样本数据的分布,帮助分析样本数据的众数、中位数等性质,横轴表示变量的取值区间,纵轴表示在该区间内数据出现的频次与区间的长度的比例。

美国人口普查局(The U.S. Census Bureau)调查了 12.4 亿人的上班通勤时间,数据如下:

起点组距频次频次/组距频次/组距/总数
0541808360.0067
551368727370.0221
1051861837230.03
1551963439260.0316
2051798135960.029
255719014380.0116
3051636932730.0264
35532126420.0052
40541228240.0066
451592006130.0049
603064612150.0017
90603435570.0005

使用直方图进行数据可视化如下

Histogram of travel time (to work), US 2000 census. Area under the curve equals the total number of cases. This diagram uses Q/width from the table.

该直方图使用单位间隔的人数(频次/组距)表示为每个矩形的高度,因此每个矩形的面积表示该区间内的人数,矩形的总面积即为 12.4 亿。

而当直方图使用(频次/组距/总数)表示为每个矩形的高度时,数据可视化如下

Histogram of travel time (to work), US 2000 census. Area under the curve equals 1. This diagram uses Q/total/width from the table.

此时,矩形的面积表示该区间所占的频率,矩形的总面积为 1,该直方图也即频率直方图

频率直方图有以下特点:

  1. 矩形面积为该区间的频率;
  2. 矩形的高度为该区间的平均频率密度。

概率密度函数

极限思维:我们使用微分思想,将频率直方图的组距一步步减小,随着组距的减小,矩形宽度越来越小,因此,在极限情况下频率直方图就会变成一条曲线,而这条曲线即为概率密度曲线。

对于概率密度曲线,我们知道:随机变量的取值落在某区域内的概率值为概率密度函数在这个区域的积分(见概率密度函数),即: P ( a < x ≤ b ) = ∫ a b f ( x ) d x P(a< x \leq b) = \int\limits_a^b f(x)dx P(a<xb)=abf(x)dx

设累积分布函数为 F ( x ) F(x) F(x),根据上述定义,则 F ( x ) = ∫ − ∞ x f ( x ) d x F(x) = \int\limits_{-\infty}^x f(x)dx F(x)=xf(x)dx

根据微分思想,则有:

f ( x 0 ) = F ( x 0 ) ˙ = lim ⁡ h → 0 F ( x 0 + h ) − F ( x 0 − h ) 2 h \begin{aligned} f(x_0) &= \dot{F(x_0)}\\ &= \lim^{}_{h \to 0}\frac{F(x_0+h)-F(x_0 - h)}{2h} \end{aligned} f(x0)=F(x0)˙=h0lim2hF(x0+h)F(x0h)

核密度估计

根据上述分析,我们应该已经明白核密度估计的目的事实上就是估测所给样本数据的概率密度函数。

公式推导

考虑一维数据,有如下 n n n 个样本数据: x 1 , x 2 , x 3 , . . . , x n x_1,x_2,x_3,...,x_n x1,x2,x3,...,xn

假设该样本数据的累积分布函数为 F ( x ) F(x) F(x),概率密度函数为 f ( x ) f(x) f(x),则有:

F ( x i − 1 < x < x i ) = ∫ x i − 1 x i f ( x ) d x F(x_{i-1} < x < x_i) = \int\limits_{x_{i-1}}^{x_i} f(x)dx F(xi1<x<xi)=xi1xif(x)dx

f ( x i ) = lim ⁡ h → 0 F ( x i + h ) − F ( x i − h ) 2 h f(x_i) = \lim^{}_{h \to 0}\frac{F(x_i+h)-F(x_i-h)}{2h} f(xi)=h0lim2hF(xi+h)F(xih)

引入累积分布函数的经验分布函数

F n ( t ) = 1 n ∑ i = 1 n 1 x i ≤ t F_n(t) = \frac{1}{n}\sum^{n}_{i=1}1_{x_i \leq t} Fn(t)=n1i=1n1xit

该函数大意为:使用 n n n 次观测中 x i ≤ t x_i \leq t xit 出现的次数与 n n n 的比值来近似描述 P ( x ≤ t ) P(x \leq t) P(xt)

将该函数代入 f ( x i ) f(x_i) f(xi),有:

f ( x i ) = lim ⁡ h → 0 1 2 n h ∑ i = 1 n 1 x i − h ≤ x j ≤ x i + h f(x_i) = \lim^{}_{h \to 0}\frac{1}{2nh}\sum^{n}_{i=1}1_{x_i-h \leq x_j \leq x_i+h} f(xi)=h0lim2nh1i=1n1xihxjxi+h

根据该公式,在实际计算中,必须给定 h h h 值, h h h 值不能太大也不能太小,太大不满足 h → 0 h \to 0 h0 的条件,太小使用的样本数据点太少,误差会很大,因此,关于 h h h 值的选择有很多研究,该值也被称为核密度估计中的带宽

确定带宽后,我们可以写出 f ( x ) f(x) f(x) 的表达式:

f ( x ) = 1 2 n h ∑ i = 1 n 1 x − h ≤ x i ≤ x + h f(x) = \frac{1}{2nh}\sum^{n}_{i=1}1_{x-h \leq x_i \leq x+h} f(x)=2nh1i=1n1xhxix+h

核函数

f ( x ) f(x) f(x) 表达式可变形为:

f ( x ) = 1 2 n h ∑ i = 1 n 1 x − h ≤ x i ≤ x + h = 1 2 n h ∑ i = 1 n K ( ∣ x − x i ∣ h ) \begin{aligned} f(x) &= \frac{1}{2nh}\sum^{n}_{i=1}1_{x-h \leq x_i \leq {x+h}}\\ &= \frac{1}{2nh}\sum^{n}_{i=1}K(\frac{|x-x_i|}{h}) \end{aligned} f(x)=2nh1i=1n1xhxix+h=2nh1i=1nK(hxxi)

其中,令 t = ∥ x − x i ∥ h t = \frac{\|x-x_i\|}{h} t=hxxi,则当 0 ≤ t ≤ 1 0 \leq t \leq 1 0t1 时, K ( t ) = 1 K(t) = 1 K(t)=1.

且:

∫ f ( x ) d x = ∫ 1 2 n h ∑ i = 1 n K ( ∣ x − x i ∣ h ) d x = ∫ 1 2 n ∑ i = 1 n K ( t ) d t = ∫ 1 2 K ( t ) d t \begin{aligned} \int f(x)dx &=\int\frac{1}{2nh}\sum^{n}_{i=1}K(\frac{|x-x_i|}{h})dx\\ &= \int\frac{1}{2n}\sum^{n}_{i=1}K(t)dt\\ &= \int\frac{1}{2} K(t)dt \end{aligned} f(x)dx=2nh1i=1nK(hxxi)dx=2n1i=1nK(t)dt=21K(t)dt

注意,此处的 ∑ i = 1 n \sum^{n}_{i=1} i=1n 指的是 n n n 次实验,而不是累计,因此计算值为 n n n

K 0 ( t ) = 1 2 K ( t ) K_0(t) = \frac{1}{2} K(t) K0(t)=21K(t),根据概率密度函数的定义,我们有:

∫ K 0 ( t ) d t = 1 \int K_0(t)dt = 1 K0(t)dt=1

其中当 0 ≤ t ≤ 1 0 \leq t \leq 1 0t1 时, K 0 ( t ) = 1 2 K_0(t) = \frac{1}{2} K0(t)=21.

此时 K 0 ( t ) K_0(t) K0(t) 就称为核函数,常用的核函数有:uniform,triangular, biweight, triweight, Epanechnikov, normal…

f ( x ) f(x) f(x) 的表达式变为:

f ( x ) = 1 n h ∑ i = 1 n K 0 ( ∣ x − x i ∣ h ) f(x) = \frac{1}{nh}\sum^{n}_{i=1}K_0(\frac{|x-x_i|}{h}) f(x)=nh1i=1nK0(hxxi)

对于二维数据, f ( x ) f(x) f(x) 为:

f ( x , y ) = 1 n h 2 ∑ i = 1 n K 0 ( d i s t ( ( x , y ) , ( x i , y i ) ) h ) f(x, y) = \frac{1}{nh^2}\sum^{n}_{i=1}K_0(\frac{dist((x, y), (x_i, y_i))}{h}) f(x,y)=nh21i=1nK0(hdist((x,y),(xi,yi)))

实验:POI 点核密度分析

技术选型

  • 栅格数据可视化:canvas
  • KFC POI 爬取:POIKit

核函数、带宽选择

使用 ArcGIS 软件说明文档提供的带宽选择方案,核函数为:

K 0 ( t ) = 3 π ( 1 − t 2 ) 2 K_0(t) = \frac{3}{\pi}(1-t^2)^2 K0(t)=π3(1t2)2

概率密度估测函数为:
f ( x , y ) = 1 n ∗ h 2 ∑ i = 1 n p o p i K 0 ( d i s t i h ) f(x, y) = \frac{1}{n*h^2}\sum_{i=1}^n pop_i K_0(\frac{dist_i}{h}) f(x,y)=nh21i=1npopiK0(hdisti)

其中, p o p i pop_i popi 为给定的权重字段,若不含有该字段,则取值为 1, n n n 为 POI 点个数。

带宽为:

h = 0.9 ∗ m i n ( A , 1 ln ⁡ ( 2 ) ∗ D m ) ∗ n − 0.2 h = 0.9*min(A,\sqrt{\frac{1}{\ln(2)}}*D_m)*n^{-0.2} h=0.9min(A,ln(2)1 Dm)n0.2

参数解释:

  • 平均中心:指 n n n 个 POI 点的平均中心,即经度和纬度分别取平均;

  • 加权平均中心:指 n n n 个 POI 点的加权平均中心,即经度和纬度分别乘以权重再取平均;

  • 标准距离计算公式:

    S D = ∑ i = 1 n ( x i − X ˉ ) 2 n + ∑ i = 1 n ( y i − Y ˉ ) 2 n + ∑ i = 1 n ( z i − Z ˉ ) 2 n SD = \sqrt{\frac{\sum_{i=1}^n(x_i-\bar X)^2}{n}+\frac{\sum_{i=1}^n(y_i-\bar Y)^2}{n}+\frac{\sum_{i=1}^n(z_i-\bar Z)^2}{n}} SD=ni=1n(xiXˉ)2+ni=1n(yiYˉ)2+ni=1n(ziZˉ)2

    其中:

    • x i , y i , z i x_i,y_i,z_i xi,yi,zi 是 POI 的坐标
    • X ˉ , Y ˉ , Z ˉ {\bar X,\bar Y, \bar Z} Xˉ,Yˉ,Zˉ 表示平均中心
    • n n n 是 POI 总数
  • 加权标准距离计算公式:

    S D w = ∑ i = 1 n w i ( x i − X ˉ w ) 2 ∑ i = 1 n w i + ∑ i = 1 n w i ( y i − Y ˉ w ) 2 ∑ i = 1 n w i + ∑ i = 1 n w i ( z i − Z ˉ w ) 2 ∑ i = 1 n w i SD_w = \sqrt{\frac{\sum_{i=1}^n w_i(x_i-\bar X_w)^2}{\sum_{i=1}^{n}w_i}+\frac{\sum_{i=1}^nw_i(y_i-\bar Y_w)^2}{\sum_{i=1}^{n}w_i}+\frac{\sum_{i=1}^nw_i(z_i-\bar Z_w)^2}{\sum_{i=1}^{n}w_i}} SDw=i=1nwii=1nwi(xiXˉw)2+i=1nwii=1nwi(yiYˉw)2+i=1nwii=1nwi(ziZˉw)2

    其中:

    • w i w_i wi 是要素 i i i 的权重
    • X ˉ w , Y ˉ w , Z ˉ w {\bar X_w,\bar Y_w, \bar Z_w} Xˉw,Yˉw,Zˉw 表示加权平均中心
    • n n n 是 POI 总数
  • 若 POI 点不含有权重字段,则 D m D_m Dm 为到平均中心距离的中值, n n n 是 POI 点数目, A A A 是标准距离 S D SD SD

  • 若 POI 点含有权重字段,则 D m D_m Dm 为到加权平均中心距离的中值, n n n 是 POI 点权重字段值的总和, A A A 是加权标准距离 S D w SD_w SDw

数据爬取

使用 POIKit,爬取河南省 KFC POI 数据,参数设置如下:

POIKit参数设置

共爬取得到 219 条数据,如下图所示:

数据展示

程序编写

核函数:

/**
 * 核函数
 * @param {Number} t 变量
 * @returns
 */
function kernel(t) {
  return (3 / Math.PI) * Math.pow(1 - t * t, 2);
}

带宽:

/**
 * 带宽
 * @param {Point[]} pts 所有POI点
 * @param {Point} avePt 平均中心
 * @returns
 */
function h(pts, avePt) {
  const SD_ = SD(pts, avePt);
  const Dm_ = Dm(pts, avePt);
  if (SD_ > Math.sqrt(1 / Math.log(2)) * Dm_) {
    return 0.9 * Math.sqrt(1 / Math.log(2)) * Dm_ * Math.pow(pts.length, -0.2);
  } else {
    return 0.9 * SD_ * Math.pow(pts.length, -0.2);
  }
}

平均中心:

/**
 * 平均中心
 * @param {Point} pts 所有POI点
 * @returns
 */
function ave(pts) {
  let lon = 0,
    lat = 0;
  pts.forEach((pt) => {
    lon += pt.lon;
    lat += pt.lat;
  });
  return new Point(lon / pts.length, lat / pts.length);
}

标准距离 SD:

/**
 * 标准距离
 * @param {Point[]} pts 所有POI点
 * @param {Point} avePt 平均中心
 * @returns
 */
function SD(pts, avePt) {
  let SDx = 0,
    SDy = 0;
  pts.forEach((pt) => {
    SDx += Math.pow(pt.lon - avePt.lon, 2);
    SDy += Math.pow(pt.lat - avePt.lat, 2);
  });
  return Math.sqrt(SDx / pts.length + SDy / pts.length);
}

Dm(到平均中心距离的中值):

/**
 * Dm
 * @param {Point[]}} pts 所有POI点
 * @param {Point} avePt 平均中心
 * @returns
 */
function Dm(pts, avePt) {
  let distance = [];
  pts.forEach((pt) => {
    distance.push(Dist(pt, avePt));
  });
  distance.sort();
  return distance[distance.length / 2];
}

核密度估计:

/**
 * 核密度估计
 * @param {Point[]} pts 所有POI点
 * @param {Rect} rect POI点边界
 * @param {Number} width 栅格图像宽度
 * @param {Number} height 栅格图像高度
 */
function kde(pts, rect, width, height) {
  const estimate = new Array(height)
    .fill(0)
    .map(() => new Array(width).fill(0));
  let min = Infinity,
    max = -Infinity;
  const avePt = ave(pts);
  const bandWidth = h(pts, avePt);
  rect.top += bandWidth;
  rect.bottom -= bandWidth;
  rect.left -= bandWidth;
  rect.right += bandWidth;
  const itemW = (rect.right - rect.left) / width;
  const itemH = (rect.top - rect.bottom) / height;
  for (let x = 0; x < width; x++) {
    const itemX = rect.left + itemW * x;
    for (let y = 0; y < height; y++) {
      const itemY = rect.bottom + itemH * y;
      let fEstimate = 0;
      for (let m = 0; m < pts.length; m++) {
        const distance = Dist(pts[m], new Point(itemX, itemY));
        if (distance < Math.pow(bandWidth, 2)) {
          fEstimate += kernel(distance / bandWidth);
        }
      }
      fEstimate = fEstimate / (pts.length * Math.pow(bandWidth, 2));
      min = Math.min(min, fEstimate);
      max = Math.max(max, fEstimate);
      estimate[height - y - 1][x] = fEstimate;
    }
  }
  return { estimate, min, max };
}

然后使用 html5 canvas 进行可视化:

/**
 * 绘制核密度估计结果栅格图
 * @param {CanvasRenderingContext2D} ctx canvas上下文
 * @param {*} param0 核密度估测值,最大值,最小值
 */
function draw(ctx, { estimate, min, max }) {
  const height = estimate.length,
    width = estimate[0].length;
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
      const val = (estimate[y][x] - min) / (max - min);
      if (val > 0 && val < 0.4) {
        ctx.fillStyle = "rgb(228, 249, 245)";
        ctx.fillRect(x, y, 1, 1);
      } else if (val >= 0.4 && val < 0.7) {
        ctx.fillStyle = "rgb(48, 227, 202)";
        ctx.fillRect(x, y, 1, 1);
      } else if (val >= 0.7 && val < 0.9) {
        ctx.fillStyle = "rgb(17, 153, 158)";
        ctx.fillRect(x, y, 1, 1);
      } else if (val >= 0.9 && val <= 1) {
        ctx.fillStyle = "rgb(64, 81, 78)";
        ctx.fillRect(x, y, 1, 1);
      }
    }
  }
}

核密度估计结果

下图是核密度估计结果:

核密度估计结果

通过该图,可发现核密度估计的结果能很好的展示数据的热点区域。

全部代码

关注微信公众号古月有三木,回复核密度分析即可获取全部代码及数据。

  • 140
    点赞
  • 618
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: 高斯核密度估计(Kernel Density Estimation,KDE)是一种用于估计概率密度函数的非参数方法。它通过将每个数据点周围的高斯核函数叠加起来来估计数据集的概率密度。 KDE的值是指在给定某一数据点处的概率密度估计值。计算KDE的值通常需要确定核函数的带宽(bandwidth)参数,它决定了核函数的宽度,即对数据点周围的影响范围。 在给定一组数据点和带宽参数后,KDE的值可以通过以下的计算过程获得: 1. 对于每个数据点,计算与该数据点距离在带宽范围内的所有其他数据点的核函数值。 2. 将所有核函数值求和并除以数据点数量,得到该数据点处的概率密度估计值。 基于高斯核函数的KDE通常具有较好的光滑性和连续性,适用于连续型数据的概率密度估计。通过调整带宽参数,可以控制估计值的平滑程度和准确性。 KDE的值可以用于多个应用场景,如异常检测、模式识别、分类等。在异常检测中,较低的KDE值可能表明该数据点具有较低的概率出现,从而可能被视为异常值。在模式识别中,可以利用KDE的值来区分不同的数据模式。在分类问题中,可以利用KDE的值来评估新数据点属于各个类别的概率,从而进行分类决策。 总之,高斯核密度估计KDE)提供了一种非参数方法来估计概率密度函数,通过将每个数据点周围的高斯核函数叠加起来来获得数据集的概率密度估计值。KDE的值可以用于多种应用场景,具有广泛的实际意义。 ### 回答2: 高斯核密度估计KDE)是一种用于估计随机变量分布的非参数方法。它的基本思想是将每个观测样本点视为一个高斯函数的中心,并根据每个样本点周围的邻域来估计密度函数的值。 KDE的计算过程如下: 1. 首先选择一个核函数,通常选择高斯函数作为核函数。 2. 对每个观测样本点,以该点为中心构建一个高斯函数。 3. 对每个高斯函数,计算该函数在各个自变量上的值。 4. 将所有高斯函数的值加权求和,得到估计密度函数的值。 在计算KDE的过程中,需要考虑两个重要的参数:核函数的带宽和观测样本点的数量。核函数的带宽决定了高斯函数对密度函数的贡献程度,较小的带宽会导致估计过于敏感,较大的带宽会导致估计过于平滑。观测样本点的数量影响到对密度函数的完整覆盖程度,较少的样本点可能会导致估计不准确。 KDE在实际应用中具有广泛的应用,例如在统计分析、数据挖掘和机器学习中。它可以用于分析数据的分布特征、寻找异常点、生成合成数据以及进行分类和聚类等任务。 总结来说,KDE是一种通过将每个观测样本点视为高斯函数的中心,根据每个样本点周围的邻域来估计密度函数的非参数方法。它能够通过调整核函数的带宽和观测样本点的数量来灵活地对不同的数据分布进行建模和估计。 ### 回答3: 高斯核密度估计KDE)是一种非参数的概率密度估计方法。它基于观测数据的分布情况,通过在每个数据点周围创建一个高斯核函数的方式来估计整体的概率密度函数。 KDE的值表示某个特定点的概率密度估计。具体来说,对于给定的输入点,KDE计算该点周围邻近点的贡献,并将它们的高斯核函数叠加在一起得到该点的概率密度估计值。 在计算过程中,KDE使用一个带宽参数来控制高斯核函数的宽度,带宽越小则高斯核函数的影响范围越小,估计的概率密度函数越细致;带宽越大则高斯核函数的影响范围越大,估计的概率密度函数越平滑。 KDE的值可以用来表示某个数据点在数据集中的相对重要性或罕见性。具体来说,KDE值较高的点表示该点周围有较多的数据点,因此被认为是数据集中的常见点;而KDE值较低的点表示该点周围较少的邻近点,因此被认为是数据集中的罕见点。 总结起来,高斯核密度估计KDE)的值代表了在给定数据点周围创建高斯核函数并叠加后得到的概率密度估计值。它可以用来衡量数据点的重要性或罕见性,并且随着带宽参数的不同而产生不同的估计结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值