一、参数估计简介
很多情况下,我们只有有限的样本集,而类条件概率密度函数p(x|ωi)和先验概率P(ωi)是未知的,需要根据已有样本进行参数估计,然后将估计值当作真实值来使用。
由给定样本集求解随机变量的分布密度函数问题是统计机器学习和概率统计学的基本问题之一。解决该问题的方法包括参数估计和非参数估计两大类:
1.参数估计方法
已知概率密度函数的形式而函数的有关参数未知,通过估计参数来估计概率密度函数的方法。有两种主要参数估计法:确定性参数估计方法是把参数看作确定而未知的, 典型方法为最大似然估计。随机参数估计方法是把未知参数当作具有某种分布的随机变量, 典型方法为贝叶斯估计。
2.非参数估计
非参数估计就是在概率密度函数形式未知条件下, 直接利用样本来推断概率密度函数。常见的非参数估计方法有核密度估计(KDE)和kN-近邻估计。和参数估计不同,非参数估计并不加入任何先验知识,而是根据数据本身的特点、性质来拟合样本集的概率分布,这样就能比参数估计方法得出更好的模型。核密度估计(KDE, Kernel Density Estimation)方法又称为Parzen窗估计(Parzen Window Estimation)或Parzen-Rosenblatt窗估计,该方法无需求解概率密度函数的参数,而用一组标准函数的叠加表示概率密度函数。简单来说,核密度估计其实是对直方图的一个自然拓展。
二、核密度估计公式及其计算

下面结合核密度估计公式(2),给出一个简单计算示例以说明核函数的使用,后面将讨论一些典型的核函数。

关于核密度估计(Parzen窗估计)方法的更多理论知识可参阅文献[1-3]。
三、核密度估计Python实践
这里使用Anaconda Jupyter Notebook及流行的Sklearn机器学习库实现核密度估计的计算。
1.导入库
在程序中导入库:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KernelDensity
from sklearn.model_selection import GridSearchCV

其中GridSearchCV库的作用就是自动调参,只要把参数输进去,它就能够返回最优模型参数的组合。
2.合成数据
为了进行核密度估计,现使用两种不同类型分布产生一个合成数据集:一种是非对称对数正态分布(使用rand.lognormal方法),另一种是高斯分布/或正态分布(使用rand.normal方法)。下面定义名为generate_data的函数,该函数将返回2000个数据点。

def generate_data(seed=17):# Fix the seed to reproduce the resultsrand = np.random.RandomState(seed)x = []dat = rand.lognormal(0, 0.3, 1000)x = np.concatenate((x, dat))dat = rand.normal(3, 1, 1000)x = np.concatenate((x, dat))return x

以下程序段将样本点存储在训练集x_train张量中,我们可以画出这些点的散点图或者画出这些点的直方图(见图1)。

x_train = generate_data()[:, np.newaxis]
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 5))
plt.subplot(121)
plt.scatter(np.arange(len(x_train)), x_train, c='green')
plt.xlabel('Sample no.')
plt.ylabel('Value')
plt.title('Scatter plot')
plt.subplot(122)
plt.hist(x_train, bins=50)
plt.title('Histogram')
fig.subplots_adjust(wspace=.3)
plt.show()


图1
3.使用Sklearn进行核密度估计
为了找到被估计密度函数的形状,我们可以生成一组彼此等距的点并估计各点的核密度。生成测试点的语句如下:

x_test = np.linspace(-1, 7, 2000)[:, np.newaxis]

现创建一个KernelDensity对象model,并使用fit()方法判定各样本得分的程序段如下:

model = KernelDensity()
model.fit(x_train)
log_dens = model.score_samples(x_test)

在Python中,使用Sklearn进行核密度估计其实十分简单,直接调用KernelDensity()方法就可以了。KernelDensity()方法的主要参数有三个:bandwidth是带宽,即核密度估计公式中的h;algorithm是加速邻近点的搜索算法如KD-Tree算法等;kernel是要选择的核函数(见下表)。

这里的KernelDensity()方法使用了默认参数,即kernel=gaussian、bandwidth=1、Ball_Tree。
下面两条语句绘制各样本点的密度分值,概率密度分布形状见图2所示。

图2
4. 理解带宽参数
前面的核密度函数估计程序段输出结果不是十分理想,主要原因是采用了(bandwidth=1)默认参数。下面程序段使用了不同带宽进行实验,以便观察带宽对密度估计的影响(见图3)。

bandwidths = [0.01, 0.05, 0.1, 0.5, 1, 4]
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(10, 7))
plt_ind = np.arange(6) + 231for b, ind in zip(bandwidths, plt_ind):kde_model = KernelDensity(kernel='gaussian', bandwidth=b)kde_model.fit(x_train)score = kde_model.score_samples(x_test)plt.subplot(ind)plt.fill(x_test, np.exp(score), c='cyan')plt.title("h="+str(b))fig.subplots_adjust(hspace=0.5, wspace=.3)
plt.show()


图3
从图3可以清晰地看到,增加带宽能得到更加平滑的估计。极小带宽值会产生尖峰和抖动的曲线,而极高带宽会产生忽略重要细节的光滑曲线。因此,为带宽参数选择适当的数值尤为重要。
5. 调整带宽参数
GridSearchCV(Cross-Validated Grid-Search,交叉验证网格搜索)允许通过多折交叉验证对带宽参数进行调优并返回参数值,其默认的交叉验证参数是三折交叉验证。该方法格式及常用参数说明如下:
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise’, return_train_score=’warn’)
●estimator:选择使用的分类器,并且传入除需要确定最佳的参数之外的其他参数。
●param_grid:需要最优化的参数的取值,值为字典或者列表,键命名必须为模型本身的参数名称。
●scoring:模型评价标准,默认None;或者如scoring=‘roc_auc’,根据所选模型不同,评价准则不同,其他常见的还有’f1’,‘accuracy’,‘recall’, , ‘average_precision’;这里的字符串(函数名)或是可调用对象需要其函数签名形如scorer(estimator, X, y),如果是默认None,则使用estimator的误差估计函数。
●cv=None,交叉验证参数,指定fold数量,默认None,使用三折交叉验证;也可以是yield训练/测试数据的生成器。
我们还可以给GridSearchCV()方法设置不同的带宽参数值。

bandwidth = np.arange(0.05, 2, .05)
kde = KernelDensity(kernel='gaussian')
grid = GridSearchCV(kde, {'bandwidth': bandwidth})
grid.fit(x_train)

最佳模型可通过GridSearchCV类对象的best_estimator_字段进行搜索。以下程序段是采用Gauss核的最佳核密度估计并显示出最佳带宽值(见图4)。

kde = grid.best_estimator_
log_dens = kde.score_samples(x_test)
plt.fill(x_test, np.exp(log_dens), c='cyan')
plt.title('Optimal estimate with Gaussian kernel')
plt.show()
print("optimal bandwidth: " + "{:.2f}".format(kde.bandwidth))


图4
从图4可以看出,带宽值=0.15时的核密度估计似乎能更好地拟合样本数据,图4的左半部符合对数正态分布,图4的右半部很好地拟合了正态分布。
6. Sklearn机器学习库提供的典型密度估计核函数
Skitlearn机器学习库提供的密度估计核函数如下:

了解核函数的最直接方式是为其画像(绘制图形)。首先,我们可用一个样本点来构建模型;接着,估计该样本点附近所有点的密度,并沿y轴绘制密度。以下程序段用来绘制6个典型核函数的图形(见图5)。

kernels = ['cosine', 'epanechnikov', 'exponential', 'gaussian', 'linear', 'tophat']
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(10, 7))
plt_ind = np.arange(6) + 231for k, ind in zip(kernels, plt_ind):kde_model = KernelDensity(kernel=k)kde_model.fit([[0]])score = kde_model.score_samples(np.arange(-2, 2, 0.1)[:, None])plt.subplot(ind)plt.fill(np.arange(-2, 2, 0.1)[:, None], np.exp(score), c='blue')plt.title(k)fig.subplots_adjust(hspace=0.5, wspace=.3)
plt.show()


7. 实验不同的核函数
下面程序段采用了不同的核函数进行实验,以观察使用不同核函数和合成数据来估计概率密度函数。可以与前面一样使用GridSearchCV()来寻找最佳带宽值。但是,对于余弦、线性和Tophat核函数会因一些-inf评分,可能导致GridSearchCV()函数执行时发出运行时警告,一种解决方案是为GridSearchCV()编写自定义评分函数。在下面程序段中,自定义评分函数my_scores()中忽略了测试点-inf评分而返回平均值。当然,采用该方案并非是处理-inf评分的最佳策略,我们也可根据已有样本数据采取其他的策略。

def my_scores(estimator, X):scores = estimator.score_samples(X)# Remove -infscores = scores[scores != float('-inf')]# Return the mean valuesreturn np.mean(scores)kernels = ['cosine', 'epanechnikov', 'exponential', 'gaussian', 'linear', 'tophat']
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(10, 7))
plt_ind = np.arange(6) + 231
h_vals = np.arange(0.05, 1, .1)for k, ind in zip(kernels, plt_ind):grid = GridSearchCV(KernelDensity(kernel=k),{'bandwidth': h_vals},scoring=my_scores)grid.fit(x_train)kde = grid.best_estimator_log_dens = kde.score_samples(x_test)plt.subplot(ind)plt.fill(x_test, np.exp(log_dens), c='cyan')plt.title(k + " h=" + "{:.2f}".format(kde.bandwidth))fig.subplots_adjust(hspace=.5, wspace=.3)
plt.show()


图6
采用不同核函数进行密度估计的实验结果见图6所示。
8. 最终的优化模型
前面介绍了采用不同核函数进行密度估计。下面程序段再对GridSearchCV()函数进行一些设置,这样不仅能发现最佳带宽,还能寻找到所使用样本数据的最佳核函数。

grid = GridSearchCV(KernelDensity(),{'bandwidth': h_vals, 'kernel': kernels},scoring=my_scores)
grid.fit(x_train)
best_kde = grid.best_estimator_
log_dens = best_kde.score_samples(x_test)
plt.fill(x_test, np.exp(log_dens), c='cyan')
plt.title("Best Kernel: " + best_kde.kernel+" h="+"{:.2f}".format(best_kde.bandwidth))
plt.show()


图7
以上程序段绘制了最终的核密度估计图,以及相应的最佳带宽及核函数参数,见图7所示。
本文介绍了采用Sklearn库对一维合成数据进行核密度估计的方法并给出了Python程序实现示例,这些示例也可推广到未知分布来源的多维数据核密度估计应用实践中。

参考文献:
1.Trevor Hastie et al. The Elements of Statistical Learning (2nd Edition), Springer.
2.李弼程等. 模式识别原理与应用, 西电版.
3.齐敏等. 模式识别导论, 清华版.
4.https://stackabuse.com
5.https://www.zhihu.com/question/27301358
6.https://en.wikipedia.org/wiki/Kernel_density_estimation

发布日期:2021年03月24日

核密度估计及其Python实践相关推荐

  1. 核密度估计python_机器学习 – 具有固定协方差的高斯核密度估计(使用python)

    我可以通过简单的运行使用scipy库执行高斯核密度估计 from scipy import stats kernel = stats.gaussian_kde(data) 但是我想将协方差修正为某个预 ...

  2. 数据的核密度估计及其可视化:Python实现

    文章目录 实例数据介绍 精神疾病治疗时长数据表 间歇泉爆发持续时间数据表 文件放置介绍 频率分布直方图法 原理探讨与分析 Python 代码实现 简单核密度估计法 原理探讨与分析 Python代码实现 ...

  3. MATLAB算法实战应用案例精讲-【数据分析】核密度估计KDE(附matlab、R语言和python代码实现)

    目录 前言 几个高频面试题目 1.如何选择KDE核密度估计的带宽 自适应或可变带宽的核密度估计

  4. 核密度估计python_核密度估计Kernel Density Estimation(KDE)

    在介绍核密度评估Kernel Density Estimation(KDE)之前,先介绍下密度估计的问题.由给定样本集合求解随机变量的分布密度函数问题是概率统计学的基本问题之一.解决这一问题的方法包括 ...

  5. 机器学习算法与Python实践之(二)支持向量机

    http://blog.csdn.net/zouxy09/article/details/17291543 机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己 ...

  6. 核密度估计python_非参数估计:核密度估计KDE

    核密度估计Kernel Density Estimation(KDE)概述 密度估计的问题 由给定样本集合求解随机变量的分布密度函数问题是概率统计学的基本问题之一.解决这一问题的方法包括参数估计和非参 ...

  7. 核密度估计Kernel Density Estimation(KDE)-代码详细解释

    在介绍核密度评估Kernel Density Estimation(KDE)之前,先介绍下密度估计的问题.由给定样本集合求解随机变量的分布密度函数问题是概率统计学的基本问题之一.解决这一问题的方法包括 ...

  8. JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式

    JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式 结构型:装饰器模式--对象装上它,就像开了挂 装饰器模式,又名装饰者模式.它的定义是"在不改变原对象的基础上,通过对其进 ...

  9. 非参数估计:核密度估计KDE

    http://blog.csdn.net/pipisorry/article/details/53635895 核密度估计Kernel Density Estimation(KDE)概述 密度估计的问 ...

最新文章

  1. js改变iframe链接
  2. 【FFmpeg】FFmpeg 帮助文档使用
  3. boost::hana::maximum用法的测试程序
  4. nowcoderD Xieldy And His Password
  5. django之视图函数
  6. 传说中的“铁索连环”?苹果要把无人车串成小火车
  7. 深度学习实践指南(四)—— 一个典型的深度学习的实践流程
  8. linux apache访问日志,linux分析apache日志获取最多访问的前10个IP
  9. cisco帧中继实验
  10. 华南师范大学计算机考研考场,2018考研:华南师范大学考场安排
  11. Office 365 之 Skype For Business电话功能试用
  12. 【SOT】SiamFC代码笔记
  13. Visual FoxPro权威指南写作原稿及光盘下载
  14. Python3爬虫实战——QQ空间自动点赞程序(上)
  15. CentOS cp 复制隐藏文件提示 cp: cannot stat ?.xxx*?. No such file or directory
  16. 方舟创建专用服务器显示黑框,方舟创建非专用游戏服务器
  17. Problem A. Snapper Chain 问题A.按扣链条 解决办法
  18. 锈永不磨灭,让末日来得更酷!
  19. Golang调用mssql存储过程
  20. 【译】UIVisualEffectView教程

热门文章

  1. [Mac] 触控板鼠标点击(mouse-click)失灵
  2. 业内人士详细介绍域名注册.cc属于什么性质?有什么特点?
  3. 安装Centos6.9后配置网络
  4. doctype作用_doctype
  5. 一课一得之通信施工与管理
  6. Idea首次提交项目到新建的git仓库
  7. 电工学学习笔记---时间常数部分
  8. 我有10个职场经验,价值100万,但今天免费|咪蒙
  9. Android Studio ADB5037端口被vschost.exe占用
  10. JSP和Servlet常见面试题