首页 > 解决方案 > 如何规范 scikit learn 的 kde?

问题描述

假设我有一个形状数组 (100000,1),表示变量 X 在 0 和 1 之间均匀分布的样本。我想估计这个变量的概率密度,我使用 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')

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])

我希望向量为 1,因为积分的总和应为 1。

标签: pythonscikit-learnkernel-density

解决方案


问题不在于规范化,我可以从一个例子中看出。假设我运行以下代码,将 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))

然后我可以使用梯形规则估计 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])

我得到的估计面积 ( my_area) 约为 0.996,非常接近 1。

问题是您的 KDE 没有处理统一 PDF 中发生在 0 和 1 处的跳跃,因此它会将它们涂抹得太多。KDE 对您的 PDF 的估计值下大约有一半的区域最终会落在那些模糊区域之下。如果您将您的值替换为X1X2 = np.linspace(-1,2,200)[:,np.newaxis]您可以看到 KDE 在 [-1,0] 和 [1,2] 区间内的 PDF 估计部分中存在显着的密度。


推荐阅读