Representing Probability Distributions¶
Introduction¶
Probability distributions such as prior distributions over model parameters
are reprented in QInfer by objects of type Distribution
that are
responsible for producing samples according to those distributions. This is
especially useful, for instance, when drawing initial particles for use with
an SMCUpdater
.
The approach to representing distributions taken by QInfer is somewhat
different to that taken by, for example, scipy.stats
, in that
a QInfer Distribution
is a class that produces samples according to
that distribution. This means that QInfer Distribution
objects provide much
less information than do those represented by objects in scipy.stats
,
but that they are much easier to write and combine.
Sampling Pre-made Distributions¶
QInfer comes along with several distributions, listed in
Specific Distributions. Each of these is a subclass of
Distribution
, and hence has a method sample()
that produces an array of samples.
>>> from qinfer import NormalDistribution
>>> dist = NormalDistribution(0, 1)
>>> samples = dist.sample(n=5)
>>> samples.shape == (5, 1)
True
Combining Distributions¶
Distribution objects can be combined using other distribution objects. For
instance, if \(a \sim \mathcal{N}(0, 1)\) and \(b \sim \text{Uni}(0, 1)\),
then the product distribution on \((a,b)\) can be produced by using
ProductDistribution
:
>>> from qinfer import UniformDistribution, ProductDistribution
>>> a = NormalDistribution(0, 1)
>>> b = UniformDistribution([0, 1])
>>> ab = ProductDistribution(a, b)
>>> samples = ab.sample(n=5)
>>> samples.shape == (5, 2)
True
Making Custom Distributions¶
To make a custom distribution, one need only implement
sample()
and set the property n_rvs
to indicate how many random variables the new distribution class represents.
For example, to implement a distribution over \(x\) and \(y\) such that \(\sqrt{x^2 + y^2} \sim \mathcal{N}(1, 0.1)\) and such that the angle between \(x\) and \(y\) is drawn from \(\text{Uni}(0, 2 \pi)\):
from qinfer import Distribution
class RingDistribution(Distribution):
@property
def n_rvs(self):
return 2
def sample(self, n=1):
r = np.random.randn(n, 1) * 0.1 + 1
th = np.random.random((n, 1)) * 2 * np.pi
x = r * np.cos(th)
y = r * np.sin(th)
return np.concatenate([x, y], axis=1)