# Distribution utility classes and functions¶

 Distribution(shape, dtype[, testval, …]) Statistical distribution Discrete([shape, dtype, defaults]) Base class for discrete distributions Continuous([shape, dtype, defaults]) Base class for continuous distributions NoDistribution(shape, dtype[, testval, …]) DensityDist(logp[, shape, dtype, testval, …]) Distribution based on a given log density function. TensorType(dtype, shape[, broadcastable]) draw_values(params[, point, size]) Draw (fix) parameter values. generate_samples(generator, \*args, \*\*kwargs) Generate samples from the distribution of a random variable.
class pymc3.distributions.Distribution(shape, dtype, testval=None, defaults=(), transform=None, broadcastable=None)

Statistical distribution

class pymc3.distributions.Discrete(shape=(), dtype=None, defaults=('mode', ), *args, **kwargs)

Base class for discrete distributions

class pymc3.distributions.Continuous(shape=(), dtype=None, defaults=('median', 'mean', 'mode'), *args, **kwargs)

Base class for continuous distributions

class pymc3.distributions.NoDistribution(shape, dtype, testval=None, defaults=(), transform=None, parent_dist=None, *args, **kwargs)
class pymc3.distributions.DensityDist(logp, shape=(), dtype=None, testval=0, random=None, wrap_random_with_dist_shape=True, check_shape_in_random=True, *args, **kwargs)

Distribution based on a given log density function.

A distribution with the passed log density function is created. Requires a custom random function passed as kwarg random to enable prior or posterior predictive sampling.

Parameters
logp: callable

A callable that has the following signature logp(value) and returns a theano tensor that represents the distribution’s log probability density.

shape: tuple (Optional): defaults to ()

The shape of the distribution. The default value indicates a scalar. If the distribution is not scalar-valued, the programmer should pass a value here.

dtype: None, str (Optional)

The dtype of the distribution.

testval: number or array (Optional)

The testval of the RV’s tensor that follow the DensityDist distribution.

random: None or callable (Optional)

If None, no random method is attached to the DensityDist instance. If a callable, it is used as the distribution’s random method. The behavior of this callable can be altered with the wrap_random_with_dist_shape parameter. The supplied callable must have the following signature: random(point=None, size=None, **kwargs), where point is a None or a dictionary of random variable names and their corresponding values (similar to what MultiTrace.get_point returns). size is the number of IID draws to take from the distribution. Any extra keyword argument can be added as required.

wrap_random_with_dist_shape: bool (Optional)

If True, the provided random callable is passed through generate_samples to make the random number generator aware of the DensityDist instance’s shape. If False, it is used exactly as it was provided.

check_shape_in_random: bool (Optional)

If True, the shape of the random samples generate in the random method is checked with the expected return shape. This test is only performed if wrap_random_with_dist_shape is False.

args, kwargs: (Optional)

These are passed to the parent class’ __init__.

Examples

with pm.Model():
mu = pm.Normal('mu',0,1)
normal_dist = pm.Normal.dist(mu, 1)
pm.DensityDist(
'density_dist',
normal_dist.logp,
observed=np.random.randn(100),
random=normal_dist.random
)
trace = pm.sample(100)


If the DensityDist is multidimensional, some care must be taken with the supplied random method. By default, the supplied random is wrapped by generate_samples() to make it aware of the multidimensional distribution’s shape. This can be prevented setting wrap_random_with_dist_shape=False. Furthermore, the size parameter is interpreted as the number of IID draws to take from this multidimensional distribution.

with pm.Model():
mu = pm.Normal('mu', 0 , 1)
normal_dist = pm.Normal.dist(mu, 1, shape=3)
dens = pm.DensityDist(
'density_dist',
normal_dist.logp,
observed=np.random.randn(100, 3),
shape=3,
random=normal_dist.random,
)
prior = pm.sample_prior_predictive(10)['density_dist']
assert prior.shape == (10, 100, 3)


If wrap_random_with_dist_shape=False, we start to get samples of an incorrect shape. By default, we can try to catch these situations.

with pm.Model():
mu = pm.Normal('mu', 0 , 1)
normal_dist = pm.Normal.dist(mu, 1, shape=3)
dens = pm.DensityDist(
'density_dist',
normal_dist.logp,
observed=np.random.randn(100, 3),
shape=3,
random=normal_dist.random,
wrap_random_with_dist_shape=False, # Is True by default
)
err = None
try:
prior = pm.sample_prior_predictive(10)['density_dist']
except RuntimeError as e:
err = e
assert isinstance(err, RuntimeError)


The default catching can be disabled with the check_shape_in_random parameter.

with pm.Model():
mu = pm.Normal('mu', 0 , 1)
normal_dist = pm.Normal.dist(mu, 1, shape=3)
dens = pm.DensityDist(
'density_dist',
normal_dist.logp,
observed=np.random.randn(100, 3),
shape=3,
random=normal_dist.random,
wrap_random_with_dist_shape=False, # Is True by default
check_shape_in_random=False, # Is True by default
)
prior = pm.sample_prior_predictive(10)['density_dist']
# We get samples with an incorrect shape
assert prior.shape != (10, 100, 3)


If you use callables that work with scipy.stats rvs, you must be aware that their size parameter is not the number of IID samples to draw from a distribution, but the desired shape of the returned array of samples. It is the user’s responsibility to wrap the callable to make it comply with PyMC3’s interpretation of size.

with pm.Model():
mu = pm.Normal('mu', 0 , 1)
normal_dist = pm.Normal.dist(mu, 1, shape=3)
dens = pm.DensityDist(
'density_dist',
normal_dist.logp,
observed=np.random.randn(100, 3),
shape=3,
random=stats.norm.rvs,
pymc3_size_interpretation=False, # Is True by default
)
prior = pm.sample_prior_predictive(10)['density_dist']
assert prior.shape == (10, 100, 3)

pymc3.distributions.TensorType(dtype, shape, broadcastable=None)
pymc3.distributions.draw_values(params, point=None, size=None)

Draw (fix) parameter values. Handles a number of cases:

1. The parameter is a scalar

2. The parameter is an RV

1. parameter can be fixed to the value in the point

2. parameter can be fixed by sampling from the RV

3. parameter can be fixed using tag.test_value (last resort)

3) The parameter is a tensor variable/constant. Can be evaluated using theano.function, but a variable may contain nodes which

1. are named parameters in the point

2. are RVs with a random method

pymc3.distributions.generate_samples(generator, *args, **kwargs)

Generate samples from the distribution of a random variable.

Parameters
generatorfunction

Function to generate the random samples. The function is expected take parameters for generating samples and a keyword argument size which determines the shape of the samples. The args and kwargs (stripped of the keywords below) will be passed to the generator function.

keyword arguments
~~~~~~~~~~~~~~~~~
dist_shapeint or tuple of int

The shape of the random variable (i.e., the shape attribute).

sizeint or tuple of int

The required shape of the samples.

broadcast_shape: tuple of int or None

The shape resulting from the broadcasting of the parameters. If not specified it will be inferred from the shape of the parameters. This may be required when the parameter shape does not determine the shape of a single sample, for example, the shape of the probabilities in the Categorical distribution.