一维核密度估计示例

核密度估计是一种估计随机变量概率密度函数的非参数方式。本示例使用一维数据来展示核密度估计的基本概念。首先,来看直方图在可视化一维数据点密度时遇到的问题。直方图可以想象为在规则网格上每个点上方堆叠一个单位“块”。然而,如上图所示,这些块的网格选择可能导致对密度分布形状的截然不同的理解。如果将每个块的中心放在它所代表的点上,得到了左下角图所示的估计。这是一个使用“顶帽”核的核密度估计。这个想法可以推广到其他核形状:第一张图的右下角图显示了相同分布上的高斯核密度估计。

Scikit-learn库通过KernelDensity估计器实现了高效的核密度估计,可以使用Ball Tree或KD Tree结构。本示例的第二张图展示了可用的核。第三张图比较了一维100个样本分布的核密度估计。尽管本示例使用的是一维分布,但核密度估计也很容易且高效地扩展到更高维度。

以下是使用Python的matplotlib和scikit-learn库实现一维核密度估计的代码示例。首先,导入必要的库,然后生成一些随机数据来模拟一维分布。接着,使用KernelDensity类来拟合这些数据,并使用不同的核函数来估计密度。最后,将结果可视化出来。

import matplotlib.pyplot as plt import numpy as np from scipy.stats import norm from sklearn.neighbors import KernelDensity # 设置随机种子以获得可重复的结果 np.random.seed(1) # 生成模拟数据 N = 100 X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)), np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis] X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis] # 绘制直方图和核密度估计 fig, ax = plt.subplots(2, 2, sharex=True, sharey=True) fig.subplots_adjust(hspace=0.05, wspace=0.05) # 绘制直方图 ax[0, 0].hist(X[:, 0], bins=np.linspace(-5, 10, 10), fc="#AAAAFF", density=True) ax[0, 0].text(-3.5, 0.31, "直方图") # 绘制偏移的直方图 ax[0, 1].hist(X[:, 0], bins=np.linspace(-5, 10, 10) + 0.75, fc="#AAAAFF", density=True) ax[0, 1].text(-3.5, 0.31, "直方图,偏移的bins") # 绘制顶帽核密度估计 kde = KernelDensity(kernel="tophat", bandwidth=0.75).fit(X) log_dens = kde.score_samples(X_plot) ax[1, 0].fill(X_plot[:, 0], np.exp(log_dens), fc="#AAAAFF") ax[1, 0].text(-3.5, 0.31, "顶帽核密度") # 绘制高斯核密度估计 kde = KernelDensity(kernel="gaussian", bandwidth=0.75).fit(X) log_dens = kde.score_samples(X_plot) ax[1, 1].fill(X_plot[:, 0], np.exp(log_dens), fc="#AAAAFF") ax[1, 1].text(-3.5, 0.31, "高斯核密度") # 绘制所有可用的核 X_plot = np.linspace(-6, 6, 1000)[:, None] X_src = np.zeros((1, 1)) fig, ax = plt.subplots(2, 3, sharex=True, sharey=True) fig.subplots_adjust(left=0.05, right=0.95, hspace=0.05, wspace=0.05) def format_func(x, loc): if x == 0: return "0" elif x == 1: return "h" elif x == -1: return "-h" else: return "%ih" % x for i, kernel in enumerate(["gaussian", "tophat", "epanechnikov", "exponential", "linear", "cosine"]): axi = ax.ravel()[i] log_dens = KernelDensity(kernel=kernel).fit(X_src).score_samples(X_plot) axi.fill(X_plot[:, 0], np.exp(log_dens), "-k", fc="#AAAAFF") axi.text(-2.6, 0.95, kernel) axi.xaxis.set_major_formatter(plt.FuncFormatter(format_func)) axi.xaxis.set_major_locator(plt.MultipleLocator(1)) axi.yaxis.set_major_locator(plt.NullLocator()) axi.set_ylim(0, 1.05) axi.set_xlim(-2.9, 2.9) ax[0, 1].set_title("可用核") # 绘制一维密度示例 N = 100 np.random.seed(1) X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)), np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis] X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis] true_dens = 0.3 * norm(0, 1).pdf(X_plot[:, 0]) + 0.7 * norm(5, 1).pdf(X_plot[:, 0]) fig, ax = plt.subplots() ax.fill(X_plot[:, 0], true_dens, fc="black", alpha=0.2, label="输入分布") colors = ["navy", "cornflowerblue", "darkorange"] kernels = ["gaussian", "tophat", "epanechnikov"] lw = 2 for color, kernel in zip(colors, kernels): kde = KernelDensity(kernel=kernel, bandwidth=0.5).fit(X) log_dens = kde.score_samples(X_plot) ax.plot(X_plot[:, 0], np.exp(log_dens), color=color, lw=lw, linestyle="-", label="kernel = '%s'" % kernel) ax.text(6, 0.38, "N=%d points" % N) ax.legend(loc="upper left") ax.plot(X[:, 0], -0.005 - 0.01 * np.random.random(X.shape[0]), "+k") ax.set_xlim(-4, 9) ax.set_ylim(-0.02, 0.4) plt.show()

上述代码首先设置了随机种子以确保结果的可重复性。然后,生成了一些模拟数据,这些数据由两个正态分布混合而成。接着,使用KernelDensity类来拟合这些数据,并使用不同的核函数来估计密度。最后,将结果可视化出来,包括直方图、顶帽核和高斯核密度估计,以及所有可用核的展示。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485