如何在python中返回通过sklearn的函数KernelDensity估计的分布的均值(或期望值)?

时间:2019-04-22 03:42:21

标签: python scikit-learn kernel-density

我的问题是,如何返回估计的“ kde”的均值和方差?还是您知道其他任何可以轻松输出均值或方差值的软件包,例如print kde.mean()print kde.get_parameter(mean)

import numpy as np
from scipy.stats import norm
from sklearn.neighbors import KernelDensity

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]
kde = KernelDensity(kernel='gaussian', bandwidth=0.5).fit(X)

2 个答案:

答案 0 :(得分:1)

通常,您需要以数字方式执行此操作。我建议两种不同的方法:

  • 集成
  • 蒙特卡洛模拟

这些方法适用于任何内核和任何带宽

集成

利用这样的事实,即一旦我们知道概率密度函数,我们就可以通过积分轻松计算均值和方差。

mean and variance

请注意,在scikit-learn中,方法score_samples返回log pdf,因此需要“ exp”它。

蒙特卡洛模拟

这里的想法是简单地从您的KDE中进行采样,并通过样本均值和方差来估计总体均值和方差。


代码

import numpy as np
from scipy.integrate import quad
from sklearn.neighbors import KernelDensity

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]

kde = KernelDensity(kernel='gaussian', bandwidth=0.5).fit(X)

# Mean and Variance - Integration
pdf = lambda x : np.exp(kde.score_samples([[x]]))[0]
mean_integration = quad(lambda x: x * pdf(x), a=-np.inf, b=np.inf)[0]
variance_integration = quad(lambda x: (x ** 2) * pdf(x), a=-np.inf, b=np.inf)[0] - mean_integration ** 2

# Mean and Variance - Monte Carlo
n_samples = 10000000
samples = kde.sample(n_samples)

mean_mc = samples.mean()
variance_mc = samples.var()


print('Mean:\nIntegration: {}\nMonte Carlo: {}\n'.format(mean_integration, mean_mc))
print('Variance\nIntegration: {}\nMonte Carlo: {}\n'.format(variance_integration, variance_mc))

输出:

  

平均值:   积分:3.560582852075697   蒙特卡罗:3.5595633705830934

     

差异:   集成度:6.645066811078639   蒙特卡洛:6.646732489654485

答案 1 :(得分:0)

原理

我遇到了同样的情况,您可以在Link库中找到期望的工作实现,但是有趣的是它正在修补statsmodels并没有在其自己的库中执行相同的功能。 / p>

他们似乎拥有scipyexpect()expect_v2(),它们在使用expect_discrete()进行数值积分的另一个答案中使用了类似的技术。

TL; DR版本

如果您像我一样懒惰,并且使用scipy.integrate.quad推断的默认采样,则可以通过用statsmodels和{{ 1}}。对于大多数用途来说,它可能“足够接近”。

density

输出:

support

四点和点之间的差异

请注意,由于缺少import numpy as np import statsmodels.api as sm import scipy 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] kde = sm.nonparametric.KDEUnivariate(X) kde.fit(kernel='gau', bw=0.5) mean1 = np.dot(kde.density, kde.support) / kde.density.sum() mean2 = scipy.integrate.quad(lambda x: kde.evaluate(x) * x, kde.support[0], kde.support[-1]) print('TL;DR version - Mean:', mean1) print('Integration version - Mean:', mean2) print('TL;DR version - Variance:', np.dot(kde.density, kde.support**2) / kde.density.sum() - mean1**2) print('Integration version - Variance:', scipy.integrate.quad(lambda x: kde.evaluate(x) * x**2, kde.support[0], kde.support[-1])[0] - mean2[0]**2) TL;DR version - Mean: 3.5605148164179368 Integration version - Mean: (3.5604536291684905, 1.9311947816995413e-08) TL;DR version - Variance: 6.646077637181225 Integration version - Variance: 6.644042199345121 方法不适用于除高斯以外的内核。例如,如果您在适合时通过quad,则唯一的方法是当前使用evaluate()。将来的版本中可能会更改。

作为一个有趣的效果,seaborn库依靠kernel='epa', fft=False来显示kde,但是由于上述原因,该库仅与高斯一起使用。对于CDF,即使指定了其他CDF,它也会显示高斯CDF。 pdf似乎仍然遵守内核规范。

参考

statsmodels.sandbox.sppatch

如果存储库发生更改,此内容也进行了复制[1月22日最新提交bfa3e69],但是,如果将此算法与numpy.dot一起使用,则可能必须将statsmodels调用替换为statsmodels调用