我想对正数据点进行内核密度估计。使用Python Scipy Stats程序包,我想到了以下代码。
def get_pdf(data):
a = np.array(data)
ag = st.gaussian_kde(a)
x = np.linspace(0, max(data), max(data))
y = ag(x)
return x, y
这对于大多数数据集都非常有效,但是对于“所有正数”数据点却给出了错误的结果。为了确保此方法正确运行,我使用数值积分来计算该曲线下的面积。
def trapezoidal_2(ag, a, b, n):
h = np.float(b - a) / n
s = 0.0
s += ag(a)[0]/2.0
for i in range(1, n):
s += ag(a + i*h)[0]
s += ag(b)[0]/2.0
return s * h
由于数据分布在区域(0,int(max(data)))中,因此在执行以下行时,我们应该获得接近1的值。
b = 1
data = st.pareto.rvs(b, size=10000)
data = list(data)
a = np.array(data)
ag = st.gaussian_kde(a)
trapezoidal_2(ag, 0, int(max(data)), int(max(data))*2)
但是当我测试时,它给出的值接近0.5。
但是当我从-100积分到max(data)时,它提供的值接近1。
trapezoidal_2(ag, -100, int(max(data)), int(max(data))*2+200)
原因是,即使原始数据集仅包含正值,ag(KDE)也定义为小于0的值。
那么如何获得仅考虑正值的核密度估计,以使区域(o,max(data))中曲线下的面积接近1?
答案 0 :(得分:1)
执行内核密度估计时,带宽的选择非常重要。我认为,斯科特定律和西尔弗曼定律与高斯相似,在分配方面效果很好。但是,它们不适用于帕累托分布。
引用doc:
带宽选择强烈影响从 KDE(远远超过内核的实际形状)。带宽选择 可以通过“经验法则”,交叉验证,“插件”来完成 方法”或其他方式;有关评论,请参见[3] ,[4] 。
gaussian_kde
使用经验法则,默认值为斯科特法则。
尝试使用不同的带宽值,例如:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
b = 1
sample = stats.pareto.rvs(b, size=3000)
kde_sample_scott = stats.gaussian_kde(sample, bw_method='scott')
kde_sample_scalar = stats.gaussian_kde(sample, bw_method=1e-3)
# Compute the integrale:
print('integrale scott:', kde_sample_scott.integrate_box_1d(0, np.inf))
print('integrale scalar:', kde_sample_scalar.integrate_box_1d(0, np.inf))
# Graph:
x_span = np.logspace(-2, 1, 550)
plt.plot(x_span, stats.pareto.pdf(x_span, b), label='theoretical pdf')
plt.plot(x_span, kde_sample_scott(x_span), label="estimated pdf 'scott'")
plt.plot(x_span, kde_sample_scalar(x_span), label="estimated pdf 'scalar'")
plt.xlabel('X'); plt.legend();
给予:
integrale scott: 0.5572130540733236
integrale scalar: 0.9999999999968957
和:
我们发现使用Scott方法的kde是错误的。