整合2D核密度估计

时间:2013-07-23 22:44:49

标签: python integration kernel-density probability-density

我有一个x,y点分布,我从中获得了KDEscipy.stats.gaussian_kde。这是我的代码以及输出的外观(x,y数据可以从here获得):

import numpy as np
from scipy import stats

# Obtain data from file.
data = np.loadtxt('data.dat', unpack=True)
m1, m2 = data[0], data[1]
xmin, xmax = min(m1), max(m1)
ymin, ymax = min(m2), max(m2)

# Perform a kernel density estimate (KDE) on the data
x, y = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([x.ravel(), y.ravel()])
values = np.vstack([m1, m2])
kernel = stats.gaussian_kde(values)
f = np.reshape(kernel(positions).T, x.shape)

# Define the number that will determine the integration limits
x1, y1 = 2.5, 1.5

# Perform integration?

# Plot the results:
import matplotlib.pyplot as plt
# Set limits
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax)
# KDE density plot
plt.imshow(np.rot90(f), cmap=plt.cm.gist_earth_r, extent=[xmin, xmax, ymin, ymax])
# Draw contour lines
cset = plt.contour(x,y,f)
plt.clabel(cset, inline=1, fontsize=10)
plt.colorbar()
# Plot point
plt.scatter(x1, y1, c='r', s=35)
plt.show()

result

坐标为(x1, y1)的红点(与2D图中的每个点一样)具有f(内核或KDE)在0和0.42之间给出的关联值。我们说f(x1, y1) = 0.08

我需要将fxy中的集成限制进行整合,其中f评估的区域为 less 而不是{{} 1}},即:f(x1, y1)

对于我所看到的f(x, y)<0.08可以通过数值积分执行函数和一维数组的集成,但我还没有看到任何可以让我执行数值积分的东西一个二维数组(python内核)此外,我不确定如何识别该特定条件给出的区域(即:f小于给定值)

这可以完成吗?

3 个答案:

答案 0 :(得分:6)

这是使用monte carlo集成的方法。它有点慢,解决方案中存在随机性。误差与样本大小的平方根成反比,而运行时间与样本大小成正比(样本大小是指monte carlo样本(在我的示例中为10000),而不是数据集的大小)。以下是使用kernel对象的一些简单代码。

#Compute the point below which to integrate
iso = kernel((x1,y1))

#Sample from your KDE distribution
sample = kernel.resample(size=10000)

#Filter the sample
insample = kernel(sample) < iso

#The integral you want is equivalent to the probability of drawing a point 
#that gets through the filter
integral = insample.sum() / float(insample.shape[0])
print integral

我得到大约0.2作为数据集的答案。

答案 1 :(得分:1)

直接的方法是integrate

import matplotlib.pyplot as plt
import sklearn
from scipy import integrate
import numpy as np

mean = [0, 0]
cov = [[5, 0], [0, 10]]
x, y = np.random.multivariate_normal(mean, cov, 5000).T
plt.plot(x, y, 'o')
plt.show()

sample = np.array(zip(x, y))
kde = sklearn.neighbors.KernelDensity().fit(sample)
def f_kde(x,y):
    return np.exp((kde.score_samples([[x,y]])))

point = x1, y1
integrate.nquad(f_kde, [[-np.inf, x1],[-np.inf, y1]])

问题是,如果你大规模地这样做,这是非常慢的。例如,如果要在x(0,100)处绘制x,y行,则需要很长时间才能计算。

注意:我使用kde中的sklearn,但我相信您也可以将其更改为其他形式。

使用原始问题中定义的kernel

import numpy as np
from scipy import stats
from scipy import integrate

def integ_func(kde, x1, y1):

    def f_kde(x, y):
        return kde((x, y))

    integ = integrate.nquad(f_kde, [[-np.inf, x1], [-np.inf, y1]])

    return integ

# Obtain data from file.
data = np.loadtxt('data.dat', unpack=True)
# Perform a kernel density estimate (KDE) on the data
kernel = stats.gaussian_kde(data)

# Define the number that will determine the integration limits
x1, y1 = 2.5, 1.5
print integ_func(kernel, x1, y1)

答案 2 :(得分:0)

当前可用

kernel.integrate_box([-np.inf,-np.inf], [2.5,1.5])