101 lines
2.4 KiB
Python
Executable File
101 lines
2.4 KiB
Python
Executable File
import numpy as np
|
|
from prml.rv.rv import RandomVariable
|
|
|
|
|
|
class MultivariateGaussian(RandomVariable):
|
|
"""
|
|
The multivariate Gaussian distribution
|
|
p(x|mu, cov)
|
|
= exp{-0.5 * (x - mu)^T @ cov^-1 @ (x - mu)}
|
|
/ (2pi)^(D/2) / |cov|^0.5
|
|
"""
|
|
|
|
def __init__(self, mu=None, cov=None, tau=None):
|
|
super().__init__()
|
|
self.mu = mu
|
|
if cov is not None:
|
|
self.cov = cov
|
|
elif tau is not None:
|
|
self.tau = tau
|
|
else:
|
|
self.cov = None
|
|
self.tau = None
|
|
|
|
@property
|
|
def mu(self):
|
|
return self.parameter["mu"]
|
|
|
|
@mu.setter
|
|
def mu(self, mu):
|
|
if isinstance(mu, np.ndarray):
|
|
assert mu.ndim == 1
|
|
self.parameter["mu"] = mu
|
|
else:
|
|
assert mu is None
|
|
self.parameter["mu"] = None
|
|
|
|
@property
|
|
def cov(self):
|
|
return self.parameter["cov"]
|
|
|
|
@cov.setter
|
|
def cov(self, cov):
|
|
if isinstance(cov, np.ndarray):
|
|
assert cov.ndim == 2
|
|
self.tau_ = np.linalg.inv(cov)
|
|
self.parameter["cov"] = cov
|
|
else:
|
|
assert cov is None
|
|
self.tau_ = None
|
|
self.parameter["cov"] = None
|
|
|
|
@property
|
|
def tau(self):
|
|
return self.tau_
|
|
|
|
@tau.setter
|
|
def tau(self, tau):
|
|
if isinstance(tau, np.ndarray):
|
|
assert tau.ndim == 2
|
|
self.parameter["cov"] = np.linalg.inv(tau)
|
|
self.tau_ = tau
|
|
else:
|
|
assert tau is None
|
|
self.tau_ = None
|
|
self.parameter["cov"] = None
|
|
|
|
@property
|
|
def ndim(self):
|
|
if hasattr(self.mu, "ndim"):
|
|
return self.mu.ndim
|
|
else:
|
|
return None
|
|
|
|
@property
|
|
def size(self):
|
|
if hasattr(self.mu, "size"):
|
|
return self.mu.size
|
|
else:
|
|
return None
|
|
|
|
@property
|
|
def shape(self):
|
|
if hasattr(self.mu, "shape"):
|
|
return self.mu.shape
|
|
else:
|
|
return None
|
|
|
|
def _fit(self, X):
|
|
self.mu = np.mean(X, axis=0)
|
|
self.cov = np.atleast_2d(np.cov(X.T, bias=True))
|
|
|
|
def _pdf(self, X):
|
|
d = X - self.mu
|
|
return (
|
|
np.exp(-0.5 * np.sum(d @ self.tau * d, axis=-1))
|
|
* np.sqrt(np.linalg.det(self.tau))
|
|
/ np.power(2 * np.pi, 0.5 * self.size))
|
|
|
|
def _draw(self, sample_size=1):
|
|
return np.random.multivariate_normal(self.mu, self.cov, sample_size)
|