我使用此处给出的公式在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()
当前,您的ker
外观(已放大)的轮廓图如下所示:
如您所见,这看起来像高斯核。您的大多数函数从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
,你将不得不采取i
并j
从-U // 2
到U // 2
。但是要解决您的分辨率问题,我建议采用U
-0.5到0.5之间的点数。
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
预期的位置。
在这种情况下,知道选择哪个范围(-0.5至0.5)取决于您的功能。例如,如果您现在使用sigma = 2
,您会发现您的总和不会再计算出来,因为现在您采样得太细了。设置你的范围是你的参数的函数-像-5 * sigma
对5 * sigma
-可能是最好的选择。