Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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