首页
学习
活动
专区
圈层
工具
发布

数据分布平滑化技术:核密度估计KDE解决直方图不连续问题

直方图密度函数在密度函数估计中存在不连续性问题,即密度值在相邻区间边界处发生突变。为获得随机变量的连续密度函数估计,核密度估计(Kernel Density Estimation, KDE)提供了有效的解决方案。

核函数

核函数本质上是密度估计中用于平滑处理的概率密度函数,通常选择对称核函数。核函数必须满足以下基本性质:非负性、曲线下面积为1、以零为中心、具有非零方差。这些约束条件保证了核函数作为概率密度函数的有效性。

核函数的核心思想在于解决直方图估计的固有缺陷。在传统直方图中,诸如[1, 3)和[3, 5)的离散区间会导致2到3之间数据点信息的丢失,产生块状且不连续的估计结果。核密度估计通过在每个数据点上放置平滑曲线(如高斯核函数K(u))来替代固定区间,曲线峰值位于数据点位置,其扩散范围覆盖数据间隙。

点x处的密度估计需要计算x与各数据点的距离(以带宽h为度量单位),然后将这些标准化距离输入核函数。距离较近的点产生较高的核函数值,距离较远的点贡献相对较小。KDE的数学表达式为:

通过单个数据点示例来解析K(x — Xi / h)的工作机制。假设K(u)为高斯核函数:

针对直方图密度估计中使用的waiting_times数据,单个数据点的核函数表现如下:

waiting_times = np.sort(waiting_times)

K = lambda u: (2 * np.pi) ** (-0.5) * np.exp(-0.5 * u ** 2)

plt.figure(figsize=(10, 6))

plt.ylim(0, 0.001)

plt.scatter(waiting_times, np.zeros_like(waiting_times), color='red', zorder=15)

for X in np.random.choice(waiting_times, size=1, replace=False):

  kernel = [(1/h) * K((x - X) / h) / len(waiting_times) for x in waiting_times]

  # we will talk about h in a bit

  plt.plot(waiting_times, kernel, color="#2C5B03")

  plt.axvline(x=X, ymin=0, color='#D08770', linestyle='-', alpha=1, linewidth=1)

当X = 75时,计算远距离点x = 50的密度贡献值会显著降低。由于高斯分布的特性,该贡献值不为零但极小,可视为可忽略的贡献量。带宽参数h的大小直接影响估计质量:

当h较小时,u值增大,将u输入核函数K(u)后,对于Xi= 75的核函数,x = 50位置的贡献变得极其微小。带宽选择是KDE成功应用的关键因素。过小的h值使每个核函数过于狭窄,导致密度估计出现过度波动和噪声,捕获随机扰动而非真实分布形状;过大的h值使核函数过于宽泛,造成过度平滑而丢失数据中的重要细节。合适的h值需要在噪声抑制和细节保留之间达到最优平衡。

Silverman经验法则

Silverman经验法则为带宽选择提供了实用的起始估计。该方法利用样本标准差σ和样本容量n计算初始带宽值。虽然并非对所有数据集都是最优选择,但在多数情况下能够有效平衡偏差和方差,因此常作为精细调优前的默认选择。

waiting_times = np.sort(waiting_times)

K = lambda u: (2 * np.pi) ** (-0.5) * np.exp(-0.5 * u ** 2)

sigma = np.std(waiting_times)

n = len(waiting_times)

h = 1.06 * sigma * n**(-1/5)

plt.figure(figsize=(10, 6))

plt.ylim(0, 0.001)

plt.scatter(waiting_times, np.zeros_like(waiting_times), color='red', zorder=15)

for X in waiting_times:

  kernel = [(1/h) * K((x - X) / h) / len(waiting_times) for x in waiting_times]

  plt.plot(waiting_times, kernel, color="#2C5B03")

  plt.axvline(x=X, ymin=0, color='#D08770', linestyle='-', alpha=1, linewidth=1)

plt.savefig("kernel_densities.png", dpi=300)

plt.tight_layout()

plt.show()

分析结果表明,样本数据均值x̄附近区域具有较高的密度值,这是因为该区域聚集了多个高核密度贡献;而远离数据点集中区域的位置(如数值10附近)则表现出较低的密度值,因为其仅接收到较低的核密度贡献。

KDE公式中距离尺度变换为h后,各核函数的面积从单位面积变为h。为恢复单位面积特性,需要将每个核函数除以h。随后对n个单位面积求和得到总面积n,通过除以n进行归一化处理,最终得到:

waiting_times = np.sort(waiting_times)

K = lambda u: (2 * np.pi) ** (-0.5) * np.exp(-0.5 * u ** 2)

sigma = np.std(waiting_times)

n = len(waiting_times)

h = 1.06 * sigma * n**(-1/5)

def f(x, h):

  kernel_values = [(1/h) * K((x - X) / h) for X in waiting_times]

  return np.sum(kernel_values) / len(waiting_times)

pdf = [f(x, h) for x in waiting_times]

plt.figure(figsize=(10, 6))

plt.plot(waiting_times, pdf, color='#E15759', linewidth=2, label='Kernel Density Estimate')

plt.xlabel("Waiting Time (minutes)", fontsize=14)

plt.ylabel("Density", fontsize=14)

plt.title("Kernel Density Estimation of Waiting Times", fontsize=16, pad=15)

plt.legend()

plt.tight_layout()

plt.savefig("kde_plot.png", dpi=300)

plt.show()

高斯核函数虽为最常用选择,但并非唯一方案。Epanechnikov核函数对邻近x的数据点赋予更高权重,同时完全忽略距离过远的点,即在特定范围外其贡献降为零。这种特性使其在计算上更为高效,因为远距离数据点不会影响x处的密度计算。Epanechnikov核函数的表达式为:

观察可见,当距离Xi超过单位距离时,贡献值降为零。

均匀核函数

均匀核函数是另一种选择方案。在该核函数中,带宽窗口内的所有点均等贡献,窗口外的点不产生贡献。实际上,使用均匀核函数的核密度估计等价于直方图密度估计器(HDE)的平滑化版本。

实际应用中无需手动实现KDE算法,现有软件库已提供完整实现。Statsmodels库的实现与手工编码逻辑一致,但密度曲线更为平滑,因为其在精细网格点上评估函数而非仅在样本值处计算。Seaborn的kdeplot函数默认使用高斯核函数并自动选择带宽参数,仅需一行代码即可生成平滑的密度曲线。

from statsmodels.nonparametric.kde import KDEUnivariate

import seaborn as sns

kde = KDEUnivariate(waiting_times)

kde.fit(kernel="gau") # gau = gaussian kernel, epa = epanechnikov kernel, uni = uniform kernel

plt.figure(figsize=(10, 6))

plt.plot(kde.support, kde.density, color='#E15759', label='Gaussian Kernel (Statsmodels)')

sns.kdeplot(waiting_times, color='#4C78A8', label='Gaussian Kernel (Seaborn)')

plt.xlabel("Waiting Time (minutes)", fontsize=14)

plt.ylabel("Density", fontsize=14)

plt.title("Different Kernels for KDE", fontsize=16, pad=15)

plt.legend()

plt.tight_layout()

plt.savefig("kde.png", dpi=300)

plt.show()

总结

直方图提供了分布的粗略概念,但存在跳跃性和块状特征。核密度估计通过在数据点上放置平滑曲线并求和的方式解决了这一问题,提供了密度的连续视图。核函数形状在实践中的影响有限,但带宽参数h至关重要,它决定了曲线是否过于嘈杂或过于平滑。Statsmodels和Seaborn等库提供的一行代码实现使得手动编程变得不再必要,但理解其底层机制对于正确应用和参数调优仍然重要。

作者:Mohith

喜欢就关注一下吧:

点个在看你最好看!

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OSGVeDfmCi24Cd2S4RxDgg-A0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券