2D高斯分布不总和为一?

时间:2016-01-11 08:33:15

标签: python numpy distribution gaussian probability-density

我使用此处给出的等式在Python中构建了一个包裹的双变量高斯分布: http://www.aos.wisc.edu/~dvimont/aos575/Handouts/bivariate_notes.pdf 但是,我不明白为什么尽管已经合并了归一化常数,但我的分布总和不能达到1。

对于U x U格子,

import numpy as np
from math import *

U = 60
m = np.arange(U)
i = m.reshape(U,1)
j = m.reshape(1,U)

sigma = 0.1
ii = np.minimum(i, U-i)
jj = np.minimum(j, U-j)
norm_constant = 1/(2*pi*sigma**2)
xmu = (ii-0)/sigma; ymu = (jj-0)/sigma
rhs = np.exp(-.5 * (xmu**2 + ymu**2))
ker = norm_constant * rhs

>> ker.sum() # area of each grid is 1 
15.915494309189533

我确信我正在思考这个问题的方式根本就缺失了,并且怀疑需要某种额外的规范化,尽管我无法绕过它。

更新:

感谢其他人提出的富有洞察力的建议,我重写了我的代码以将L1规范化应用于内核。然而,似乎在通过FFt进行2D卷积的情况下,将范围保持为[0,U]仍然能够返回令人信服的结果:

U = 100
Ukern = np.copy(U)
#Ukern = 15

m = np.arange(U)
i = m.reshape(U,1)
j = m.reshape(1,U)

sigma = 2.
ii = np.minimum(i, Ukern-i)
jj = np.minimum(j, Ukern-j)
xmu = (ii-0)/sigma; ymu = (jj-0)/sigma
ker = np.exp(-.5 * (xmu**2 + ymu**2))
ker /= np.abs(ker).sum()

''' Point Density '''
ido = np.random.randint(U, size=(10,2)).astype(np.int)
og = np.zeros((U,U))
np.add.at(og, (ido[:,0], ido[:,1]), 1)

''' Convolution via FFT and inverse-FFT '''
v1 = np.fft.fft2(ker)
v2 = np.fft.fft2(og)
v0 = np.fft.ifft2(v2*v1)
dd = np.abs(v0)

plt.plot(ido[:,1], ido[:,0], 'ko', alpha=.3)
plt.imshow(dd, origin='origin')
plt.show()

enter image description here 另一方面,使用注释掉的行调整内核大小会给出错误的情节:

enter image description here

2 个答案:

答案 0 :(得分:4)

目前,ker的(大幅放大)轮廓图如下所示: Contour plot of current kernel

正如您所看到的,这看起来与高斯内核完全不同。你的大部分功能从0到1消失。看看内核本身就会发现所有的值确实真的很快就会消失:

>>> ker[0:5, 0:5]
array([[  1.592e+001,   3.070e-021,   2.203e-086,   5.879e-195,   0.000e+000],
       [  3.070e-021,   5.921e-043,   4.248e-108,   1.134e-216,   0.000e+000],
       [  2.203e-086,   4.248e-108,   3.048e-173,   8.136e-282,   0.000e+000],
       [  5.879e-195,   1.134e-216,   8.136e-282,   0.000e+000,   0.000e+000],
       [  0.000e+000,   0.000e+000,   0.000e+000,   0.000e+000,   0.000e+000]])

你得到的15.915的总和值基本上只是ker [0,0]。所有这些告诉你的是你没有正确构建网格。

请记住,在计算机上创建内核时,您必须在适当的位置对其进行采样。过于粗略地采样会导致你的总和不正确。

首先,如果您想要以mu=0为中心的完整密度,则必须从ij-U // 2U // 2。但是为了解决您的分辨率问题,我建议在-0.5和0.5之间取U个分数。

import numpy as np
import matplotlib.pyplot as plt

U = 60
m = np.linspace(-0.5, 0.5, U)    # 60 points between -1 and 1
delta = m[1] - m[0]              # delta^2 is the area of each grid cell
(x, y) = np.meshgrid(m, m)       # Create the mesh

sigma = 0.1
norm_constant = 1 / (2 * np.pi * sigma**2)

rhs = np.exp(-.5 * (x**2 + y**2) / sigma**2)
ker = norm_constant * rhs
print(ker.sum() * delta**2)

plt.contour(x, y, ker)
plt.axis('equal')
plt.show()

这会产生接近1.0的总和,并且内核以mu=0为中心。 Contour plot of corrected kernel

在这种情况下,知道选择的范围(-0.5到0.5)取决于您的功能。例如,如果您现在使用sigma = 2,您会发现您的金额将无法再次使用,因为现在您的过于精细。将您的范围设置为参数的函数 - 例如-5 * sigma5 * sigma - 可能是最佳选择。

答案 1 :(得分:3)

注意:如下面的评论中所述,此解决方案仅在您尝试构建高斯卷积核(或高斯滤波器)用于图像处理时才有效。它不是一个正确归一化的高斯密度函数,但它是用于从图像中去除高斯噪声的形式。

您缺少L1规范化:

ker /= np.abs(ker).sum()

这会使你的内核表现得像一个实际的密度函数。由于您的网格的值可能会有很大差异,因此需要进行上述标准化步骤。

事实上,你所拥有的高斯nornalization常数可能只是使用上面的L1规范。如果我没有注意到,你正试图创建一个高斯卷积,上面是通常的规范化技术。

正如@Praveen所说,你的第二个错误就是你需要从[-U//2, U//2]中抽取网格。你可以这样做:

i, j = np.mgrid[-U//2:U//2+1, -U//2:U//2+1]

最后,如果你要做的是构建一个高斯滤波器,那么内核的大小通常是从sigma(以避免远离中心的零点)估算为U//2 <= t * sigma,其中t }是截断参数,通常设置为t=3t=4