creating a multivariate skew normal distribution python

百般思念 提交于 2021-01-05 11:36:56

问题


How can I create a multivariate skew normal function, where then by inputting x and y points we can create a surface diagram in 3d (x,y and z coordinates)


回答1:


I wrote a blog post about this, but here is complete working code:

from   matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from   scipy.stats import (multivariate_normal as mvn,
                           norm)


class multivariate_skewnorm:
    
    def __init__(self, a, cov=None):
        self.dim  = len(a)
        self.a    = np.asarray(a)
        self.mean = np.zeros(self.dim)
        self.cov  = np.eye(self.dim) if cov is None else np.asarray(cov)

    def pdf(self, x):
        return np.exp(self.logpdf(x))
        
    def logpdf(self, x):
        x    = mvn._process_quantiles(x, self.dim)
        pdf  = mvn(self.mean, self.cov).logpdf(x)
        cdf  = norm(0, 1).logcdf(np.dot(x, self.a))
        return np.log(2) + pdf + cdf


xx   = np.linspace(-2, 2, 100)
yy   = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(xx, yy)
pos  = np.dstack((X, Y))

fig  = plt.figure(figsize=(10, 10), dpi=150)
axes = [
    fig.add_subplot(1, 3, 1, projection='3d'),
    fig.add_subplot(1, 3, 2, projection='3d'),
    fig.add_subplot(1, 3, 3, projection='3d')
]

for a, ax in zip([[0, 0], [5, 1], [1, 5]], axes):
    Z = multivariate_skewnorm(a=a).pdf(pos)
    ax.plot_surface(X, Y, Z, cmap=cm.viridis)
    ax.set_title(r'$\alpha$ = %s, cov = $\mathbf{I}$' % str(a), fontsize=18)

That code will generate this figure:




回答2:


You can add direction to multivariate normal distribution by adding a sigma covariance matrix:

import numpy as np
from scipy.stats import multivariate_normal

mu = [20,20] # center of distribution.
sigma_size_top, sigma_size_bot = np.random.uniform(5, 20, size=2)
cov_max = np.sqrt(sigma_size_top * sigma_size_bot) * 0.9 # Cov max can't be larger than sqrt of the other elements
sigma_cov = np.random.uniform(-cov_max, cov_max)
sigma = np.array([[sigma_size_top, sigma_cov],[sigma_cov, sigma_size_bot]])

And then pass it in to your multivariate_normal:

dist = multivariate_normal(mu, sigma)

Put this into a 2D mapping by:

x = np.linspace(0, 40, 41)
y = x.copy()
xx, yy = np.meshgrid(x, y)
pos = np.empty(xx.shape + (2,))
pos[:, :, 0] = xx
pos[:, :, 1] = yy
my_map = dist.pdf(pos)

You'll then have a skewed multivariate normal distribution on a matrix. I suggest you scale this matrix as the values will be small.



来源:https://stackoverflow.com/questions/52975883/creating-a-multivariate-skew-normal-distribution-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!