def compute_perrakis_estimate(marginal_sample, lnlikefunc, lnpriorfunc, lnlikeargs=(), lnpriorargs=(), densityestimation='histogram', **kwargs): """ Computes the Perrakis estimate of the bayesian evidence. The estimation is based on n marginal posterior samples (indexed by s, with s = 0, ..., n-1). :param array marginal_sample: A sample from the parameter marginal posterior distribution. Dimensions are (n x k), where k is the number of parameters. :param callable lnlikefunc: Function to compute ln(likelihood) on the marginal samples. :param callable lnpriorfunc: Function to compute ln(prior density) on the marginal samples. :param tuple lnlikeargs: Extra arguments passed to the likelihood function. :param tuple lnpriorargs: Extra arguments passed to the lnprior function. :param str densityestimation: The method used to estimate the marginal posterior density of each model parameter ("normal", "kde", or "histogram"). Other parameters ---------------- :param kwargs: Additional arguments passed to estimate_density function. :return: References ---------- Perrakis et al. (2014; arXiv:1311.0674) """ if not isinstance(marginal_sample, np.ndarray): marginal_sample = np.array(marginal_sample) number_parameters = marginal_sample.shape[1] ## # Estimate marginal posterior density for each parameter. marginal_posterior_density = np.zeros(marginal_sample.shape) for parameter_index in range(number_parameters): # Extract samples for this parameter. x = marginal_sample[:, parameter_index] # Estimate density with method "densityestimation". marginal_posterior_density[:, parameter_index] = \ estimate_density(x, method=densityestimation, **kwargs) # Compute produt of marginal posterior densities for all parameters prod_marginal_densities = marginal_posterior_density.prod(axis=1) ## ## # Compute lnprior and likelihood in marginal sample. log_prior = lnpriorfunc(marginal_sample, *lnpriorargs) log_likelihood = lnlikefunc(marginal_sample, *lnlikeargs) ## # Mask values with zero likelihood (a problem in lnlike) cond = log_likelihood != 0 # Use identity for summation # http://en.wikipedia.org/wiki/List_of_logarithmic_identities#Summation.2Fsubtraction # ln(sum(x)) = ln(x[0]) + ln(1 + sum( exp( ln(x[1:]) - ln(x[0]) ) ) ) # log_summands = log_likelihood[cond] + np.log(prior_probability[cond]) # - np.log(prod_marginal_densities[cond]) log_summands = (log_likelihood[cond] + log_prior[cond] - np.log(prod_marginal_densities[cond])) perr = lib.log_sum(log_summands) - log(len(log_summands)) return perr
def compute_perrakis_estimate(marginal_sample, lnlikefunc, lnpriorfunc, lnlikeargs=(), lnpriorargs=(), densityestimation='histogram', **kwargs): """ Computes the Perrakis estimate of the bayesian evidence. The estimation is based on n marginal posterior samples (indexed by s, with s = 0, ..., n-1). :param array marginal_sample: A sample from the parameter marginal posterior distribution. Dimensions are (n x k), where k is the number of parameters. :param callable lnlikefunc: Function to compute ln(likelihood) on the marginal samples. :param callable lnpriorfunc: Function to compute ln(prior density) on the marginal samples. :param tuple lnlikeargs: Extra arguments passed to the likelihood function. :param tuple lnpriorargs: Extra arguments passed to the lnprior function. :param str densityestimation: The method used to estimate the marginal posterior density of each model parameter ("normal", "kde", or "histogram"). Other parameters ---------------- :param kwargs: Additional arguments passed to estimate_density function. :return: References ---------- Perrakis et al. (2014; arXiv:1311.0674) """ if not isinstance(marginal_sample, np.ndarray): marginal_sample = np.array(marginal_sample) number_parameters = marginal_sample.shape[1] ## # Estimate marginal posterior density for each parameter. marginal_posterior_density = np.zeros(marginal_sample.shape) for parameter_index in range(number_parameters): # Extract samples for this parameter. x = marginal_sample[:, parameter_index] # Estimate density with method "densityestimation". marginal_posterior_density[:, parameter_index] = \ estimate_density(x, method=densityestimation, **kwargs) # Compute produt of marginal posterior densities for all parameters prod_marginal_densities = marginal_posterior_density.prod(axis=1) ## ## # Compute lnprior and likelihood in marginal sample. log_prior = lnpriorfunc(marginal_sample, *lnpriorargs) log_likelihood = lnlikefunc(marginal_sample, *lnlikeargs) ## # Mask values with zero likelihood (a problem in lnlike) cond = log_likelihood != 0 # Use identity for summation # http://en.wikipedia.org/wiki/List_of_logarithmic_identities#Summation.2Fsubtraction # ln(sum(x)) = ln(x[0]) + ln(1 + sum( exp( ln(x[1:]) - ln(x[0]) ) ) ) # log_summands = log_likelihood[cond] + np.log(prior_probability[cond]) # - np.log(prod_marginal_densities[cond]) log_summands = (log_likelihood[cond] + log_prior[cond] - np.log(prod_marginal_densities[cond]) ) perr = lib.log_sum(log_summands) - log(len(log_summands)) return perr
def compute_harmonicmean(lnlike_post, posterior_sample=None, lnlikefunc=None, lnlikeargs=(), **kwargs): """ Computes the harmonic mean estimate of the marginal likelihood. The estimation is based on n posterior samples (indexed by s, with s = 0, ..., n-1), but can be done directly if the log(likelihood) in this sample is passed. :param array lnlike_post: log(likelihood) computed over a posterior sample. 1-D array of length n. If an emply array is given, then compute from posterior sample. :param array posterior_sample: A sample from the parameter posterior distribution. Dimensions are (n x k), where k is the number of parameters. If None the computation is done using the log(likelihood) obtained from the posterior sample. :param callable lnlikefunc: Function to compute ln(likelihood) on the marginal samples. :param tuple lnlikeargs: Extra arguments passed to the likelihood function. Other parameters ---------------- :param int size: Size of sample to use for computation. If none is given, use size of given array or posterior sample. References ---------- Kass & Raftery (1995), JASA vol. 90, N. 430, pp. 773-795 """ if len(lnlike_post) == 0 and posterior_sample is not None: samplesize = kwargs.pop('size', len(posterior_sample)) if samplesize < len(posterior_sample): posterior_subsample = numpy.random.choice(posterior_sample, size=samplesize, replace=False) else: posterior_subsample = posterior_sample.copy() # Compute log likelihood in posterior sample. log_likelihood = lnlikefunc(posterior_subsample, *lnlikeargs) elif len(lnlike_post) > 0: samplesize = kwargs.pop('size', len(lnlike_post)) log_likelihood = numpy.random.choice(lnlike_post, size=samplesize, replace=False) # Use identity for summation # http://en.wikipedia.org/wiki/List_of_logarithmic_identities#Summation.2Fsubtraction # ln(sum(x)) = ln(x[0]) + ln(1 + sum( exp( ln(x[1:]) - ln(x[0]) ) ) ) hme = -lib.log_sum(-log_likelihood) + log(len(log_likelihood)) return hme