Rap*_*zra 6 python kernel-density scikit-learn
假设我有一个形状为 (100000,1) 的数组,表示 0 到 1 之间均匀分布的变量 X 的样本。我想近似该变量的概率密度,我使用 Scikit-Learn KernelDensity 来做到这一点。
问题是我只得到一个未标准化的结果。概率密度的积分总和不等于1。我应该如何自动归一化?难道我做错了什么 ?
def kde_sklearn(data, grid, **kwargs):
"""
Kernel Density Estimation with Scikit-learn
Parameters
----------
data : numpy.array
Data points used to compute a density estimator. It
has `n x p` dimensions, representing n points and p
variables.
grid : numpy.array
Data points at which the desity will be estimated. It
has `m x p` dimensions, representing m points and p
variables.
Returns
-------
out : numpy.array
Density estimate. Has `m x 1` dimensions
"""
kde_skl = KernelDensity(**kwargs)
kde_skl.fit(data)
# score_samples() returns the log-likelihood of the samples
log_pdf = kde_skl.score_samples(grid)
return np.exp(log_pdf)
X = np.random.uniform(0,1,1000).reshape(-1,1)
X1 = np.linspace(0,1,100)[:,np.newaxis]
kde_sklearn(X,X1,kernel='tophat')
Run Code Online (Sandbox Code Playgroud)
Out[43]:
array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5])
Run Code Online (Sandbox Code Playgroud)
我预计向量为 1,因为积分之和应为 1。
问题不在于标准化,正如我可以从一个例子中看出的那样。假设我运行以下代码,将 KDE 拟合到标准正态分布的样本:
import numpy as np
import sklearn.neighbors as sn
# Sample from a standard normal distribution
XX = np.random.randn(1000).reshape(-1, 1)
# Fit a KDE
kde_sklg = sn.KernelDensity()
kde_sklg.fit(XX)
# Get estimated densities
XX1 = np.linspace(-4.0, 4.0, 100)[:, np.newaxis]
gdens = np.exp(kde_sklg.score_samples(XX1))
Run Code Online (Sandbox Code Playgroud)
然后我可以使用梯形规则估计 PDF 下的面积,如下所示:
my_area = 0.0
for i in range(1,gdens.shape[0]):
my_area += 0.5*(gdens[i] + gdens[i-1])*(XX1[i,0] - XX1[i-1,0])
Run Code Online (Sandbox Code Playgroud)
我得到的估计面积 ( my_area) 约为 0.996,非常接近 1。
问题在于您的 KDE 无法处理统一 PDF 中 0 和 1 处发生的跳转,因此它会将它们涂抹得太多。KDE 对 PDF 的估计下大约一半的区域最终会出现在这些被涂抹的区域下方。如果将您的值替换X1为X2 = np.linspace(-1,2,200)[:,np.newaxis],您可以看到 KDE 的 PDF 估计值在区间 [-1,0] 和 [1,2] 上有显着的密度。