Source code for gmmmc.priors.prior
import abc
import numpy as np
import scipy.stats
from gmmmc import GMM
[docs]class GMMPrior():
def __init__(self, means_prior, covars_prior, weights_prior):
"""
Containing class for the priors of a GMM. Initialised with priors of means, weights & covariances.
Parameters
----------
means_prior : GMMParameterPrior
Prior for the means of the GMM
covars_prior : GMMParameterPrior
Prior for the covariances of the GMM
weights_prior : GMMParameterPrior
Prior for the weights of the GMM
"""
self.means_prior = means_prior
self.covars_prior = covars_prior
self.weights_prior = weights_prior
[docs] def log_prob(self, gmm):
"""
Parameters
----------
gmm : GMM
object containing parameters
Returns
-------
: double
log prior probability of the parameters of the input GMM
"""
logprob = 0
logprob += self.means_prior.log_prob(gmm.means)
logprob += self.covars_prior.log_prob(gmm.covars)
logprob += self.weights_prior.log_prob(gmm.weights)
return logprob
[docs] def sample(self):
"""
Compute a sample from the prior distribution of the GMM's parameters.
Returns
-------
: GMM
GMM object containing the sampled parameters
"""
return GMM(self.means_prior.sample(), self.covars_prior.sample(), self.weights_prior.sample())
[docs]class GMMParameterPrior:
@abc.abstractmethod
[docs] def log_prob(self, params):
"""
Calculate the log prior probability.
Parameters
----------
params : array_like of varying shape
parameters for a GMM e.g means weights covariances
Returns
-------
: double
log prior probability of the parameters
"""
pass
@abc.abstractmethod
[docs] def log_prob_single(self, param, mixture_num):
"""
Compute log probability of a single set of parameters (mean/covariance/weight) vector
Parameters
----------
param : 1-D array_like vector of parameters for a single mixture
mixture_num : Mixture index for the parameters.
Returns
-------
: double
log prior probability of parameters
"""
pass
[docs]class MeansGaussianPrior(GMMParameterPrior):
def __init__(self, prior_means, covariances):
"""
Multivariate Gaussian prior distribution for GMM means.
Each mean vector for the means has its own Gaussian prior. Diagonal covariances for the means.
Parameters
----------
prior_means : 2-D array_like of shape (n_mixtures, n_features)
Expected means for each mixture of the GMM
covariances : 2-D array_like of shape (n_mixtures, n_features)
Diagonal covariances of the expected means of the GMM. Alters the 'width' of the prior.
"""
# shape should be (n_mixtures, n_features)
self.means = prior_means
self.covars = covariances
self.distributions = [scipy.stats.multivariate_normal(self.means[i], self.covars[i])\
for i in xrange(self.means.shape[0])]
try:
self.n_features = prior_means.shape[1]
except:
raise ValueError("Means must be 2d")
[docs] def log_prob(self, means):
"""Compute the log prior probability of the means of a GMM according to Gaussian priors.
Parameters
----------
means : 2-D array_like, of shape (n_mixtures, n_features)
mean vectors for the GMM
Returns
-------
: double
Proportional to the log probability of the means of the GMM
"""
log_prob = np.sum([self.log_prob_single(means[i], i) for i in xrange(len(self.distributions))])
return log_prob
[docs] def log_prob_single(self, mean, mixture_num):
"""Compute the log probability of the means for a specific mixture.
Parameters
----------
mean : 1-D array_like of length n_features
Single mean vector from a single mixture of the GMM.
mixture_num : int
Index of the mixture for the mean.
Returns
-------
: double
Proportional to the log prior probability for means
"""
return self.distributions[mixture_num].logpdf(mean)
[docs] def sample(self):
"""
Draw a sample from the Gaussian prior distributions of the mean vectors.
Returns
-------
: 2-D array_like of shape (n_mixtures, n_features)
Return a complete set of mean vectors for a GMM
"""
return np.array([[normal.rvs()] if self.n_features == 1 else normal.rvs() for normal in self.distributions])
[docs]class MeansUniformPrior(GMMParameterPrior):
def __init__(self, low, high, n_mixtures, n_features):
"""
Uniform prior for the means of a GMM.
Parameters
----------
low : double
Upper limit for uniform distribution.
high : double
Lower limit for uniform distribution.
n_mixtures : int
Number of mixtures in GMM.
n_features : int
Dimensionality of the feature space.
"""
self.low = low
self.high = high
self.n_mixtures = n_mixtures
self.n_features = n_features
[docs] def log_prob(self, means):
"""
Compute the log prior probability of the means of a GMM. Since this will be used for monte carlo simulations,
we care only that it is proportional to the true probability. For a uniform distribution we can
use any value.
Parameters
----------
means : 2-D array_like, of shape (n_mixtures, n_features)
mean vectors for the GMM
Returns
-------
: double
Proportional to the log probability of the means of the GMM.
0.0 if the means are within the bounds of the uniform prior, -inf otherwise.
"""
# only care about proportional.
if (means < self.low).any() or (means > self.high).any():
return -np.inf
else:
return 0.0
[docs] def log_prob_single(self, mean, mixture):
"""
Compute the log probability of the means for a specific mixture.
Parameters
----------
mean : 1-D array_like of length n_features
Single mean vector from a single mixture of the GMM.
mixture_num : int
Index of the mixture for the mean.
Returns
-------
: double
Proportional to the log prior probability for means
0.0 if the means are within the bounds of the uniform prior, -inf otherwise.
"""
if (mean < self.low).any() or (mean > self.high).any():
# if invalid value
return -np.inf
else:
return 0.0
[docs] def sample(self):
# sample means
return np.random.uniform(self.low, self.high, size=(self.n_mixtures, self.n_features))
[docs]class DiagCovarsUniformPrior(GMMParameterPrior):
def __init__(self, low, high, n_mixtures, n_features):
"""
Uniform prior for a diagonal covariance matrix in a GMM.
Parameters
----------
low : double
Lower limit for uniform distribution. Must be greater than 0.
high : double
Upper limit for uniform distribution.
n_mixtures : int
Number of mixtures in GMM.
n_features : int
Dimensionality of the feature space.
"""
self.low = low
self.high = high
self.n_mixtures = n_mixtures
self.n_features = n_features
[docs] def log_prob(self, covars):
"""
Compute the log prior probability of the covariances of a GMM.
Since this will be used for monte carlo simulations, we care only that it is proportional to
the true probability. For a uniform distribution we can use any value.
Parameters
----------
covars : 2-D array_like, of shape (n_mixtures, n_features)
covariance vectors for the GMM
Returns
-------
: double
Proportional to the log probability of the covariance of the GMM.
0.0 if the means are within the bounds of the uniform prior, -inf otherwise.eans
"""
if (covars < self.low).any() or (covars > self.high).any():
return -np.inf
else:
# return some constant value
return 0.0
[docs] def log_prob_single(self, covar, mixture_num):
"""
Compute the log probability of the covariances for a specific mixture.
Parameters
----------
covar : 1-D array_like of length n_features
Single diagonal covariance from a single mixture of the GMM.
mixture_num : int
Index of the mixture for the covariance matrix.
Returns
-------
double
Proportional to the log prior probability for the covariance.
0.0 if the means are wimeansthin the bounds of the uniform prior, -inf otherwise.
"""
if (covar < self.low).any() or (covar > self.high).any():
return -np.inf
else:
# return some constant value
return 0.0
[docs] def sample(self):
"""
Draw a sample for the diagonals of a covariance matrix assuming a uniform prior over each individual element.
Returns
-------
: 2-D array_like of shape (n_mixtures, n_features)
array of diagonal covariances for a GMM.
"""
return np.random.uniform(self.low, self.high, size=(self.n_mixtures, self.n_features))
[docs]class CovarsStaticPrior(GMMParameterPrior):
def __init__(self, prior_covars):
"""
Prior for covariance assuming that we know its true value.
i.e a probability of 1 at prior_covars and 0 otherwise.
Parameters
----------
prior_covars : 2-D array_like of shape (n_mixtures, n_features)
Assumed true values of covariance matrices for GMM
"""
self.prior_covars = prior_covars
[docs] def log_prob(self, covariances):
"""
Log probability of a covariance given we know what its true value 'should' be.
Parameters
----------
covariances : covariance matrices of GMM distribution
Returns
-------
: double
0 if covariances are identical to their true values, -inf otherwise.
"""
# assign probability of 1 to the static covariance prior
if np.allclose(self.prior_covars, covariances):
return 0.0
else:
return -np.inf
[docs] def log_prob_single(self, covariance, mixture_num):
"""
Log probability of a covariance matrix of a single mixture given we know what its true value should be.
Parameters
----------
covariance : 1-D array_like of shape (n_features)
covariance matrix for a specific mixture in GMM
mixture_num : int
Index of mixture in GMM
Returns
-------
: double
0 if covariance is identical to its true value, -inf otherwise
"""
if np.allclose(self.prior_covars[mixture_num], covariance):
return 0.0
else:
return -np.inf
[docs]class WeightsUniformPrior(GMMParameterPrior):
def __init__(self, n_mixtures):
"""
Uniform Prior for Weights (Dirichlet distribution with all parameters equal to 1)
Parameters
----------
n_mixtures : int
number of mixtures in the GMM
"""
self.alpha = [1 for _ in xrange(n_mixtures)]
self.dirichlet = scipy.stats.dirichlet(self.alpha)
[docs] def log_prob(self, weights):
"""
Returns a log probability according to uniform dirichlet prior.
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
Weight vector for mixture. Must lie on the normal simplex.
Returns
-------
: double
log probability under uniform prior.
"""
return self.dirichlet.logpdf(weights)
[docs] def log_prob_single(self, weights, mixture_num):
"""
Functionally the same as log_prob
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
Weight vector for mixture. Must lie on the normal simplex.
mixture_num : not used in this context
Returns
-------
: double
log probability under uniform prior.
"""
return self.dirichlet.logpdf(weights)
[docs] def sample(self):
"""
Draw sample from dirichlet distribution
Returns
-------
: 1-D array_like of shape (n_mixtures)
Set of weight parameters for a GMM.
"""
return np.random.dirichlet(self.alpha, 1)[0]
[docs]class WeightsStaticPrior(GMMParameterPrior):
def __init__(self, prior_weights):
"""
Prior for Weights assuming it has a true fixed value.
Parameters
----------
n_mixtures : int
number of mixtures in the GMM
"""
self.prior_weights = prior_weights
[docs] def log_prob(self, weights):
"""
Returns a log probability assuming weights have a true fixed value.
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
Weight vector for mixture. Must lie on the normal simplex.
Returns
-------
: double
0 if weights are close to true values, -inf otherwise
"""
if np.all(np.isclose(weights, self.prior_weights)):
return 0.0
else:
return -np.inf
[docs] def log_prob_single(self, weights, mixture_num):
"""
Functionally the same as log_prob
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
Weight vector for mixture. Must lie on the normal simplex.
mixture_num : int
Not used.
Returns
-------
: double
0 if weights are close to true values, -inf otherwise
"""
return self.log_prob(weights)
[docs] def sample(self):
"""
Sample true weight vector
Returns
-------
: 1-D array_like with shape (n_mixtures)
true weights.
"""
return np.array(self.prior_weights)
[docs]class WeightsDirichletPrior(GMMParameterPrior):
def __init__(self, alpha):
"""
Dirichlet prior for the weights of a GMM
Parameters
----------
alpha : 1-D array_like of shape (n_mixtures)
Parameters of the dirichlet distribution.
Notes
----------
Alphas of the dirichlet distribution can be set to the expected weights. (e.g those found by ML estimation)
"""
self.alpha = alpha
[docs] def log_prob(self, weights):
"""
Calculate log probability of weight vector according to dirichlet prior.
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
Returns
-------
: double
log probability under distribution
"""
return scipy.stats.dirichlet.logpdf(weights, self.alpha)
[docs] def log_prob_single(self, weights, mixture_num):
"""
Identical to log_prob
Parameters
----------
weights : 1-D array_like of shape (n_mixtures)
mixture_num : unused
Returns
-------
: double
log probability under distribution
"""
return self.log_prob(weights)
[docs] def sample(self):
"""
Sample from dirichlet distribution.
Returns
-------
: 1-D array like of shape (n_mixtures)
Sample weights from dirichlet distribution.
"""
return np.random.dirichlet(self.alpha)