直方图与核密度估计

直方图,密度估计 · 浏览次数 : 64

小编点评

**核密度估计 (KDE) 方法** 核密度估计 (KDE) 方法是一种用于近似概率密度函数的概率分布方法。它使用一系列波包的组合来构建一个连续可微分的概率密度函数。 **基本步骤:** 1. 将数据转换为与概率分布相关的变量。 2. 选择一个波包函数作为核密度估计函数。 3. 计算核密度估计函数的期望值。 4. 使用核密度估计函数来计算概率密度。 **优点:** * 能够处理非正态分布。 * 具有较高的精度。 * 近似连续概率密度函数。 **缺点:** * 需要大量的样本数量才能获得准确的估计。 * 核密度估计函数的准确性受边界条件的影响。

正文

技术背景

直方图是一种经常被用于统计的图形表达形式,简单来说它的功能就是用一系列的样本数据,去分析样本的分布规律。而直方图跟核密度估计(Kernel Density Estimation,KDE)方法的主要差别在于,直方图得到的是一个离散化的统计分布,而KDE方法得到的是一个连续的概率分布函数。如果将得到的分布重新用于采样,两者都可以结合蒙特卡洛方法实现这样的功能,但是KDE的优点在于它得到的结果是可微分的,那么就可以应用于有偏估计的分子动力学模拟中,如元动力学(Meta Dynamics)方法。这里主要用Python实现一个简单的KDE函数的功能,也顺带介绍一下Numpy和Matplotlib中关于直方图的使用方法。

制备样本

在使用直方图和KDE前,我们需要先制备一些样本,这里可以使用Numpy生成一些随机数,便于测试,例如均匀随机数,其概率密度为:

\[f(x)=\left\{ \begin{matrix} \frac{1}{b-a}, a<x<b\\ 0, others \end{matrix} \right. \]

对应的numpy生成方法为:

data = np.random.uniform(-3, 3, (10000, ))

这个分布表示在-3到3的范围内进行均匀随机采样,采10000个样本点。还可以使用高斯分布,其概率密度为:

\[f(x)=\frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} \]

对应的numpy生成方法为:

data = np.random.normal(0, 1, (10000, ))

这个采样表示从\(\mu=0, \sigma=1\)的条件下对高斯函数进行采10000个样本点,也就是正态分布。还有一种比较常见的指数分布:

\[f(x)=ax^{a-1},0\le x\le 1,a>0 \]

对应的numpy的采样方法为:

data = np.random.power(5, 10000)

这里配置参数\(a=5\),采10000个样本点。这种采样方法,随着\(x\)的增长,概率密度会越来越大。

核密度估计函数

首先我们可以给出核密度估计函数的形式:

\[f(x)=\frac{\sum_{t=1}^M\omega_tK(x-x_t,\sigma)}{\sum_{t=1}^M\omega_t} \]

其中\(K(x-x_t,\sigma)\)表示一个带宽为\(\sigma\)的核函数,比如这里我们可以选用前面提到的高斯函数(或者简化为正态分布),用其他的函数作为波包也是可以的。值得注意的是,这里的带宽\(\sigma\)可以理解为波包宽度的设定。从高斯函数的表达形式也可以看出来,当\(x=\mu\)\(f(x)\)取得最大值\(f_{max}=\frac{1}{\sqrt{2\pi}\sigma}\)\(\sigma\)的值越大,\(f_{max}\)的值就越小,那么波包的辐射范围就会越广,也就是所谓的带宽越大。

按照KDE的这种算法,假定我们用高斯函数为核函数,那么理论上应该用一个for循环来实现:

for t in range(0, M):
    for index in range(0, len(grids)):
        grids[index] += omega[t] * gaussian(x[index] - xt, sigma)

但是因为在Numpy中支持了自动广播的机制,因此我们只需要一行代码就可以完成整个for循环里面的计算:

grids = gaussian(z[None] - x[:, None], sigma=sigma).sum(axis=0)

完整示例

我们可以先用一个小样本示例,看一下核密度估计函数到底在做什么:

import numpy as np
import matplotlib.pyplot as plt

def gaussian(x, mu=0, sigma=1):
    “”“高斯波包函数“””
    return np.exp(-(x-mu)**2/2/sigma**2)/np.sqrt(2*np.pi)/sigma

def kde(x, grid_min, grid_max, bins, sigma):
    “”“带归一化的核密度估计函数”“”
    grid_size = (grid_max - grid_min) / bins
    z = grid_size*np.arange(bins) + grid_min + grid_size/2
    res = gaussian(z[None]-x[:, None], sigma=sigma).sum(axis=0) / x.shape[-1]
    res /= res.sum()*grid_size
    return res, z

plt.figure(figsize=(10, 9))
plt.title('Kernel Density Estimation')
# 正态分布采样
data = np.random.normal(0, 1, (3, ))
# Numpy生成的直方图参数
hist, bin_edges = np.histogram(data, bins=20, normed=True)
subplot1 = plt.subplot2grid((4, 3), (0, 0))
subplot1.set_title("Matplotlib Hist")
subplot1.set_ylabel("Normal Distribution")
# Matplotlib自带的直方图
subplot1.hist(data, bins=20, rwidth=0.9, color='black', density=True)
subplot2 = plt.subplot2grid((4, 3), (0, 1))
subplot2.set_title("Numpy Histogram")
subplot2.bar(bin_edges[:-1], hist, width=0.15, color='green', align='center')
subplot3 = plt.subplot2grid((4, 3), (0, 2))
subplot3.set_title("KDE Function")
# 三种不同带宽的核密度估计函数
k, z = kde(data, -3, 3, 30, 0.2)
subplot3.plot(z, k, color='orange', label=r'$\sigma$=0.2')
k, z = kde(data, -3, 3, 30, 0.6)
subplot3.plot(z, k, color='purple', label=r'$\sigma$=0.6')
k, z = kde(data, -3, 3, 30, 1.0)
subplot3.plot(z, k, color='red', label=r'$\sigma$=1.0')
subplot3.legend()
# 有偏置的正态分布
data = np.random.normal(0, 1, (3, )) + 1
hist, bin_edges = np.histogram(data, bins=20, normed=True)
subplot1 = plt.subplot2grid((4, 3), (1, 0))
subplot1.set_ylabel("Bias Normal Distribution")
subplot1.hist(data, bins=20, rwidth=0.9, color='black', density=True)
subplot2 = plt.subplot2grid((4, 3), (1, 1))
subplot2.bar(bin_edges[:-1], hist, width=0.15, color='green', align='center')
subplot3 = plt.subplot2grid((4, 3), (1, 2))
k, z = kde(data, -3, 3, 30, 0.2)
subplot3.plot(z, k, color='orange', label=r'$\sigma$=0.2')
k, z = kde(data, -3, 3, 30, 0.6)
subplot3.plot(z, k, color='purple', label=r'$\sigma$=0.6')
k, z = kde(data, -3, 3, 30, 1.0)
subplot3.plot(z, k, color='red', label=r'$\sigma$=1.0')
subplot3.legend()
# 指数分布
data = np.random.power(5, 3)*7-4
hist, bin_edges = np.histogram(data, bins=20, normed=True)
subplot1 = plt.subplot2grid((4, 3), (2, 0))
subplot1.set_ylabel("Exponential Distribution")
subplot1.hist(data, bins=20, rwidth=0.9, color='black', density=True)
subplot2 = plt.subplot2grid((4, 3), (2, 1))
subplot2.bar(bin_edges[:-1], hist, width=0.15, color='green', align='center')
subplot3 = plt.subplot2grid((4, 3), (2, 2))
k, z = kde(data, -3, 3, 30, 0.2)
subplot3.plot(z, k, color='orange', label=r'$\sigma$=0.2')
k, z = kde(data, -3, 3, 30, 0.6)
subplot3.plot(z, k, color='purple', label=r'$\sigma$=0.6')
k, z = kde(data, -3, 3, 30, 1.0)
subplot3.plot(z, k, color='red', label=r'$\sigma$=1.0')
subplot3.legend()
# 均匀分布
data = np.random.uniform(-3, 3, (3, ))
hist, bin_edges = np.histogram(data, bins=20, normed=True)
subplot1 = plt.subplot2grid((4, 3), (3, 0))
subplot1.set_ylabel("Uniform Distribution")
subplot1.hist(data, bins=20, rwidth=0.9, color='black', density=True)
subplot2 = plt.subplot2grid((4, 3), (3, 1))
subplot2.bar(bin_edges[:-1], hist, width=0.15, color='green', align='center')
subplot3 = plt.subplot2grid((4, 3), (3, 2))
k, z = kde(data, -3, 3, 30, 0.2)
subplot3.plot(z, k, color='orange', label=r'$\sigma$=0.2')
k, z = kde(data, -3, 3, 30, 0.6)
subplot3.plot(z, k, color='purple', label=r'$\sigma$=0.6')
k, z = kde(data, -3, 3, 30, 1.0)
subplot3.plot(z, k, color='red', label=r'$\sigma$=1.0')
subplot3.legend()
# 画图
plt.show()

得到的结果如下图所示:

在这个结果中我们看到,因为采样比较稀疏,直方图只会显示被采到的那个格点,而核密度估计函数则是以波包的形式,将采样概率密度辐射到整个的采样空间上,这就实现了一个连续化。如果把采样密度调大一点,比如我们调整为采样10000次,那么得到的结果是这样的:

这也表明,只有足够多的样本数量,才能够相对准确的复原出采样的分布函数,而且这跟边界条件的连续性有比较大的关系。

总结概要

核密度估计(KDE)方法,相当于用多个波包的组合形式来近似一个真实的概率密度,以获得一个连续可微分的概率密度函数。本文通过一些简单的概率分布的示例,演示了一下KDE的使用方法。其实KDE的思想在很多领域都会以不同的形式出现,是一个比较基础的概率分布近似手段。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/kde.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

与直方图与核密度估计相似的内容:

直方图与核密度估计

核密度估计(KDE)方法,相当于用多个波包的组合形式来近似一个真实的概率密度,以获得一个连续可微分的概率密度函数。本文通过一些简单的概率分布的示例,演示了一下KDE的使用方法。其实KDE的思想在很多领域都会以不同的形式出现,是一个比较基础的概率分布近似手段。

R语言基于表格文件的数据绘制具有多个系列的柱状图与直方图

本文介绍基于R语言中的readxl包与ggplot2包,读取Excel表格文件数据,并绘制具有多个系列的柱状图、条形图的方法~

Python从零到壹丨图像增强及运算:图像掩膜直方图和HS直方图

摘要:本章主要讲解图像直方图相关知识点,包括掩膜直方图和HS直方图,并通过直方图判断黑夜与白天,通过案例分享直方图的实际应用。 本文分享自华为云社区《[Python从零到壹] 五十二.图像增强及运算篇之图像掩膜直方图和HS直方图》,作者: eastmount。 一.图像掩膜直方图 如果要统计图像的某

Python批量读取HDF多波段栅格数据并绘制像元直方图

本文介绍基于Python语言gdal模块,实现多波段HDF栅格图像文件的读取、处理与像元值可视化(直方图绘制)等操作~

Python按条件筛选、剔除表格数据并绘制剔除前后的直方图

本文介绍基于Python语言,读取Excel表格文件数据,以其中某一列数据的值为标准,对于这一列数据处于指定范围的所有行,再用其他几列数据的数值,加以数据筛选与剔除;同时,对筛选前、后的数据分别绘制若干直方图,并将结果数据导出保存为一个新的Excel表格文件的方法~

Oracle使用临时表与直接关联的性能比较

Oracle使用临时表与直接关联的性能比较 摘要 自己的数据库水平还是太low了. 之前有很多店理解过. 但是一直理解的不深入. 比如我们这边有很多使用临时表存储中间结果数据 然后对结果数据进行关联查询的 直接关联查询 SELECT col.TABLE_NAME, col.column_name F

QUIC在京东直播的应用与实践

本文将分别从推流端、中台源站、直播云CDN及播放端四个部分串烧式地介绍与直播相关的一些技术实践,并重点介绍QUIC技术的应用情况及收益。

真·Redis缓存优化—97%的优化率你见过嘛?

本文通过一封618前的R2M(公司内部缓存组件,可以认为等同于Redis)告警,由浅入深的分析了该告警的直接原因与根本原因,并根据原因提出相应的解决方法,希望能够给大家在排查类似问题时提供相应的思路。

驱动开发:内核封装WSK网络通信接口

本章`LyShark`将带大家学习如何在内核中使用标准的`Socket`套接字通信接口,我们都知道`Windows`应用层下可直接调用`WinSocket`来实现网络通信,但在内核模式下应用层API接口无法使用,内核模式下有一套专有的`WSK`通信接口,我们对WSK进行封装,让其与应用层调用规范保持一致,并实现内核与内核直接通过`Socket`通信的案例。

【转帖】47.直接内存

目录 1.直接内存概述2.`IO`与`NIO`对比3.直接内存的`OOM`与内存大小设置 1.直接内存概述 1.直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。 2.直接内存是在Java堆外,直接向系统申请的内存空间 3.Java的NIO库允许使用直接内存,用于数据