使用 scipy 的 gaussian_kde 和 sklearn 的 KernelDensity 进行核密度估计会导致不同的结果

Posted

技术标签:

【中文标题】使用 scipy 的 gaussian_kde 和 sklearn 的 KernelDensity 进行核密度估计会导致不同的结果【英文标题】:Kernel Density Estimation using scipy's gaussian_kde and sklearn's KernelDensity leads to different results 【发布时间】:2021-09-24 12:21:03 【问题描述】:

我从两个叠加的正态分布中创建了一些数据,然后应用 sklearn.neighbors.KernelDensityscipy.stats.gaussian_kde 来估计密度函数。但是,使用相同的带宽 (1.0) 和相同的内核,两种方法都会产生不同的结果。有人可以解释一下原因吗?感谢您的帮助。

您可以在下面找到重现问题的代码:

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
import seaborn as sns
from sklearn.neighbors import KernelDensity

n = 10000
dist_frac = 0.1
x1 = np.random.normal(-5,2,int(n*dist_frac))
x2 = np.random.normal(5,3,int(n*(1-dist_frac)))
x = np.concatenate((x1,x2))
np.random.shuffle(x)
eval_points = np.linspace(np.min(x), np.max(x))

kde_sk = KernelDensity(bandwidth=1.0, kernel='gaussian')
kde_sk.fit(x.reshape([-1,1]))
y_sk = np.exp(kde_sk.score_samples(eval_points.reshape(-1,1)))

kde_sp = gaussian_kde(x, bw_method=1.0)
y_sp = kde_sp.pdf(eval_points)

sns.kdeplot(x)
plt.plot(eval_points, y_sk)
plt.plot(eval_points, y_sp)
plt.legend(['seaborn','scikit','scipy'])

如果我将 scipy 带宽更改为 0.25,两种方法的结果看起来大致相同。

【问题讨论】:

【参考方案1】:

scipy.stats.gaussian_kde 和 sklearn.neighbors.KernelDensity 中的带宽是什么意思是不一样的。 Scipy.stats.gaussian_kde 使用带宽因子https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.gaussian_kde.html。对于一维核密度估计,应用以下公式:

sklearn.neighbors.KernelDensity 的带宽 = scipy.stats.gaussian_kde 的带宽因子 * 样本的标准差

根据您的估计,这可能意味着您的标准差等于 4。

我想参考Getting bandwidth used by SciPy's gaussian_kde function了解更多信息。

【讨论】:

【参考方案2】:

增加“随机正常”的大小。你的数据点太少了。 尝试使用n=500000 并检查结果。

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于使用 scipy 的 gaussian_kde 和 sklearn 的 KernelDensity 进行核密度估计会导致不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

使用 scipy 的 gaussian_kde 和 sklearn 的 KernelDensity 进行核密度估计会导致不同的结果

gaussian_filter 和 gaussian_kde 中 sigma 和带宽的关系

`python`中的加权高斯核密度估计

在 scipy 中创建新的发行版

sklearn 中的 2D KDE 带宽与 scipy 中的带宽之间的关系

如何估计密度函数并计算其峰值?