简体   繁体   English

如何绘制具有不同西格玛的二维高斯?

[英]How to plot a 2d gaussian with different sigma?

I am trying to make and plot a 2d gaussian with two different standard deviations.我正在尝试制作和绘制具有两个不同标准差的二维高斯。 They give the equation on mathworld: http://mathworld.wolfram.com/GaussianFunction.html but I can't seem to get a proper 2D array which centers it around zero.他们给出了关于 mathworld 的方程: http ://mathworld.wolfram.com/GaussianFunction.html 但我似乎无法得到一个以零为中心的正确二维数组。

I got this, but it does not quite work.我得到了这个,但它并不完全有效。

x = np.array([np.arange(size)])
y = np.transpose(np.array([np.arange(size)]))

psf  = 1/(2*np.pi*sigma_x*sigma_y) * np.exp(-(x**2/(2*sigma_x**2) + y**2/(2*sigma_y**2))) 

Your function is centred on zero but your coordinate vectors are not.您的函数以零为中心,但您的坐标向量不是。 Try:尝试:

size = 100
sigma_x = 6.
sigma_y = 2.

x = np.linspace(-10, 10, size)
y = np.linspace(-10, 10, size)

x, y = np.meshgrid(x, y)
z = (1/(2*np.pi*sigma_x*sigma_y) * np.exp(-(x**2/(2*sigma_x**2)
     + y**2/(2*sigma_y**2))))

plt.contourf(x, y, z, cmap='Blues')
plt.colorbar()
plt.show()

Probably this answer is too late for @Coolcrab , but I would like to leave it here for future reference.可能这个答案对@Coolcrab 来说太晚了,但我想把它留在这里以备将来参考。

You can use a multivariate Gaussian formula as follows您可以使用多元高斯公式如下

在此处输入图片说明

changing the mean elements changes the origin, while changing the covariance elements changes the shape (from circle to ellipse).改变平均元素会改变原点,而改变协方差元素会改变形状(从圆形到椭圆形)。

在此处输入图片说明

Here is the code:这是代码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

# Our 2-dimensional distribution will be over variables X and Y
N = 40
X = np.linspace(-2, 2, N)
Y = np.linspace(-2, 2, N)
X, Y = np.meshgrid(X, Y)

# Mean vector and covariance matrix
mu = np.array([0., 0.])
Sigma = np.array([[ 1. , -0.5], [-0.5,  1.]])

# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y

def multivariate_gaussian(pos, mu, Sigma):
    """Return the multivariate Gaussian distribution on array pos."""

    n = mu.shape[0]
    Sigma_det = np.linalg.det(Sigma)
    Sigma_inv = np.linalg.inv(Sigma)
    N = np.sqrt((2*np.pi)**n * Sigma_det)
    # This einsum call calculates (x-mu)T.Sigma-1.(x-mu) in a vectorized
    # way across all the input variables.
    fac = np.einsum('...k,kl,...l->...', pos-mu, Sigma_inv, pos-mu)

    return np.exp(-fac / 2) / N

# The distribution on the variables X, Y packed into pos.
Z = multivariate_gaussian(pos, mu, Sigma)

# plot using subplots
fig = plt.figure()
ax1 = fig.add_subplot(2,1,1,projection='3d')

ax1.plot_surface(X, Y, Z, rstride=3, cstride=3, linewidth=1, antialiased=True,
                cmap=cm.viridis)
ax1.view_init(55,-70)
ax1.set_xticks([])
ax1.set_yticks([])
ax1.set_zticks([])
ax1.set_xlabel(r'$x_1$')
ax1.set_ylabel(r'$x_2$')

ax2 = fig.add_subplot(2,1,2,projection='3d')
ax2.contourf(X, Y, Z, zdir='z', offset=0, cmap=cm.viridis)
ax2.view_init(90, 270)

ax2.grid(False)
ax2.set_xticks([])
ax2.set_yticks([])
ax2.set_zticks([])
ax2.set_xlabel(r'$x_1$')
ax2.set_ylabel(r'$x_2$')

plt.show()

For that you can use the multivariate_normal() from the scipy package like this:为此,您可以使用 scipy 包中的multivariate_normal() ,如下所示:

# Imports
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D

# Data
x = np.linspace(-10, 10, 500)
y = np.linspace(-10, 10, 500)
X, Y = np.meshgrid(x,y)

# Multivariate Normal
mu_x = np.mean(x)
sigma_x = np.std(x)
mu_y = np.mean(y)
sigma_y = np.std(y)
rv = multivariate_normal([mu_x, mu_y], [[sigma_x, 0], [0, sigma_y]])

# Probability Density
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y
pd = rv.pdf(pos)

# Plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, pd, cmap='viridis', linewidth=0)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Probability Density')
plt.title("Multivariate Normal Distribution")
plt.show()

Your Gaussian is centered on (0,0) so set up the axes around this origin.你的高斯以 (0,0) 为中心,所以围绕这个原点设置轴。 For example,例如,

In [40]: size = 200

In [41]: sigma_x,sigma_y = 50, 20

In [42]: x = np.array([np.arange(size)]) - size/2
In [43]: y = np.transpose(np.array([np.arange(size)])) - size /2
In [44]: psf  = 1/(2*np.pi*sigma_x*sigma_y) *
                np.exp(-(x**2/(2*sigma_x**2) + y**2/(2*sigma_y**2)))

In [45]: pylab.imshow(psf)
Out[45]: <matplotlib.image.AxesImage at 0x10bc07f10>

In [46]: pylab.show()

在此处输入图片说明

I think this is indeed not very friendly.我觉得这确实不是很友好。 I will write here the code and explain why it works.我将在这里编写代码并解释它为什么起作用。

The equation of a multivariate gaussian is as follows:多元高斯方程如下:

多元高斯

In the 2D case,在二维情况下, X and亩 are 2D column vectors,是二维列向量, 西格玛 is a 2x2 covariance matrix and n=2 .是一个 2x2 协方差矩阵且n=2

So in the 2D case, the vector所以在二维情况下,向量X is actually a point (x,y) , for which we want to compute function value, given the 2D mean vector实际上是一个点(x,y) ,我们想要计算函数值,给定 2D 均值向量亩 , which we can also write as (mX, mY) , and the covariance matrix ,我们也可以写成(mX, mY) ,以及协方差矩阵西格玛 . .

To make it more friendly to implement, let's compute the result of为了更友好地实现,让我们计算结果表达式 :

So所以x-亩 is the column vector (x - mX, y - mY) .向量(x - mX, y - mY) Therefore, the result of computing因此,计算结果在此处输入图片说明 is the 2D row vector:是二维行向量:

(CI[0,0] * (x - mX) + CI[1,0] * (y - mY) , CI[0,1] * (x - mX) + CI[1,1] * (y - mY)) , where CI is the inverse of the covariance matrix, shown in the equation as (CI[0,0] * (x - mX) + CI[1,0] * (y - mY) , CI[0,1] * (x - mX) + CI[1,1] * (y - mY)) ,其中CI是协方差矩阵的逆矩阵,在等式中显示为有说服力 , which is a 2x2 matrix, like ,这是一个 2x2 矩阵,如西格玛 is.是。

Then, the current result, which is a 2D row vector, is multiplied (inner product) by the column vector然后,当前结果,即二维行向量,乘以列向量(内积) x-亩 , which finally gives us the scalar : ,这最终给了我们标量

CI[0,0](x - mX)^2 + (CI[1,0] + CI[0,1])(y - mY)(x - mX) + CI[1,1](y - mY)^2 CI[0,0](x - mX)^2 + (CI[1,0] + CI[0,1])(y - mY)(x - mX) + CI[1,1](y - mY )^2

This is going to be easier to implement this expression using NumPy, in comparison to与使用 NumPy 相比,使用 NumPy 实现这个表达式会更容易表达式 , even though they have the same value. ,即使它们具有相同的值。

>>> m = np.array([[0.2],[0.6]])  # defining the mean of the Gaussian (mX = 0.2, mY=0.6)
>>> cov = np.array([[0.7, 0.4], [0.4, 0.25]])   # defining the covariance matrix
>>> cov_inv = np.linalg.inv(cov)  # inverse of covariance matrix
>>> cov_det = np.linalg.det(cov)  # determinant of covariance matrix
# Plotting
>>> x = np.linspace(-2, 2)
>>> y = np.linspace(-2, 2)
>>> X,Y = np.meshgrid(x,y)
>>> coe = 1.0 / ((2 * np.pi)**2 * cov_det)**0.5
>>> Z = coe * np.e ** (-0.5 * (cov_inv[0,0]*(X-m[0])**2 + (cov_inv[0,1] + cov_inv[1,0])*(X-m[0])*(Y-m[1]) + cov_inv[1,1]*(Y-m[1])**2))
>>> plt.contour(X,Y,Z)
<matplotlib.contour.QuadContourSet object at 0x00000252C55773C8>
>>> plt.show()

The result:结果:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM