Source code for bayspec.util.post
"""Container for posterior samples of a single parameter."""
import numpy as np
[docs]
class Post:
"""Posterior sample and its summary statistics for one parameter.
Holds a 1D array of posterior draws together with an optional matching
array of log-probabilities, and exposes common point estimates and
credible intervals.
Attributes:
sample: 1D array of posterior draws.
logprob: Matching log-probability for each draw, or ``None``.
"""
def __init__(self, sample, logprob=None):
"""Store ``sample`` and optionally its log-probabilities.
Args:
sample: 1D array of posterior draws.
logprob: Matching log-probability for each draw. Required for
``best`` to be defined.
"""
self._sample = sample
self._logprob = logprob
@property
def sample(self):
return self._sample
@sample.setter
def sample(self, new_sample):
if not (np.ndim(new_sample) == 1):
raise ValueError('sample must be 1D arrays')
else:
self._sample = new_sample
@property
def logprob(self):
return self._logprob
@logprob.setter
def logprob(self, new_logprob):
if not (np.ndim(new_logprob) == 1):
raise ValueError('logprob must be 1D arrays')
else:
self._logprob = new_logprob
@property
def nsample(self):
"""Number of posterior draws."""
return self.sample.shape[0]
@property
def mean(self):
"""Sample mean of the posterior draws."""
return np.mean(self.sample)
@property
def median(self):
"""Sample median of the posterior draws."""
return np.median(self.sample)
@property
def best(self):
"""Draw with the highest log-probability, or ``None`` if unavailable."""
if self.logprob is None:
return None
else:
return self.sample[np.argmax(self.logprob)]
@property
def best_ci(self):
return getattr(self, '_best_ci', None)
@best_ci.setter
def best_ci(self, new_best_ci):
self._best_ci = new_best_ci
@property
def truth(self):
return getattr(self, '_truth', None)
@truth.setter
def truth(self, new_truth):
self._truth = new_truth
[docs]
def quantile(self, q):
"""Return the ``q``-quantile of the sample.
Args:
q: Probability (or array of probabilities) in ``[0, 1]``.
Returns:
The corresponding sample quantile.
"""
return np.quantile(self.sample, q)
[docs]
def interval(self, q):
"""Return the central credible interval containing probability ``q``.
Args:
q: Requested central probability mass, between 0 and 1.
Returns:
``[low, high]`` bounding the central interval.
"""
return np.quantile(self.sample, [0.5 - q / 2, 0.5 + q / 2]).tolist()
@property
def Isigma(self):
"""One-sigma (68.27%) central credible interval."""
return self.interval(68.27 / 100)
@property
def IIsigma(self):
"""Two-sigma (95.45%) central credible interval."""
return self.interval(95.45 / 100)
@property
def IIIsigma(self):
"""Three-sigma (99.73%) central credible interval."""
return self.interval(99.73 / 100)
[docs]
def error(self, par, q=0.6827):
"""Return the asymmetric errors of ``par`` against the ``q``-interval.
Args:
par: Reference point estimate (e.g. best fit or median).
q: Central credible level. Defaults to one sigma.
Returns:
``[lower_error, upper_error]`` -- signed differences between
``par`` and the interval endpoints.
"""
ci = self.interval(q)
return np.diff([ci[0], par, ci[1]]).tolist()
@property
def info(self):
"""Dictionary of mean, median, best, and one-sigma interval."""
return dict(
[
('mean', self.mean),
('median', self.median),
('best', self.best),
('Isigma', self.Isigma),
]
)