distributions
distributions
Define random-number-safe distributions.
Classes
Name | Description |
---|---|
Dist | Base class for tracking one random number generator associated with one distribution, |
Dists | Class for managing a collection of Dist objects |
multi_random | A class for holding two or more ss.random() distributions, and generating |
scale_types | Define how distributions scale |
Dist
distributions.Dist(self,
=None,
dist=None,
distname=None,
name=None,
unit=None,
seed=None,
offset=True,
strict=True,
auto=None,
sim=None,
module=False,
mock=False,
debug**kwargs,
)
Base class for tracking one random number generator associated with one distribution, i.e. one decision per timestep.
See ss.dist_list
for a full list of supported distributions. Parameter inputs tend to follow SciPy’s, rather than NumPy’s, definitions (although in most cases they’re the same). See also ss.distributions.scale_types
for more information on how different distributions scale by time.
Note: by default, ss.Dist
is initialized with an ss.Sim
object to ensure random number reproducibility. You can override this with either ss.Dist(strict=False)
on creation, or dist.init(force=True)
after creation.
Although it’s possible in theory to define a custom distribution (i.e., not one from NumPy or SciPy), in practice this is difficult. The distribution needs to have both a way to return random variates (easy), as well as the probability point function (inverse CDF). In addition, the distribution must be able to take a NumPy RNG as its bit generator. It’s easier to just use a default Dist (e.g., ss.random()), and then take its output as input (i.e., quantiles) for whatever custom distribution you want to create.
Parameters
Name | Type | Description | Default |
---|---|---|---|
dist | rv_generic |
optional; a scipy.stats distribution (frozen or not) to get the ppf from |
None |
distname | str | the name for this class of distribution (e.g. “uniform”) | None |
name | str | the name for this particular distribution (e.g. “age_at_death”) | None |
unit | str/ss.TimePar |
if provided, convert the output of the distribution to a timepar (e.g. rate or duration); can also be inferred from distribution parameters (see examples below) | None |
seed | int | the user-chosen random seed (e.g. 3) | None |
offset | int | the seed offset; will be automatically assigned (based on hashing the name) if None | None |
strict | bool | if True, require initialization and invalidate after each call to rvs() | True |
auto | bool | whether to auto-reset the state after each draw | True |
sim | Sim | usually determined on initialization; the sim to use as input to callable parameters | None |
module | Module | usually determined on initialization; the module to use as input to callable parameters | None |
mock | int | if provided, then initialize with a mock Sim object (of size mock ) for debugging purposes |
False |
debug | bool | print out additional detail | False |
kwargs | dict | parameters of the distribution | {} |
Examples:
# Create a Bernoulli distribution
p_death = ss.bernoulli(p=0.1).init(force=True)
p_death.rvs(50) # Create 50 draws
# Create a normal distribution that's also a timepar
dur_infection = ss.normal(loc=12, scale=2, unit='years')
dur_infection = ss.years(ss.normal(loc=12, scale=2)) # Same as above
dur_infection = ss.normal(loc=ss.years(12), scale=2)) # Same as above
dur_infection = ss.normal(loc=ss.years(12), scale=ss.months(24)) # Same as above, perform time unit conversion internally
dur_infection.init(force=True).plot_hist() # Show results
# Create a distribution manually
dist = ss.Dist(dist=sps.norm, loc=3).init(force=True)
dist.rvs(10) # Return 10 normally distributed random numbers
Attributes
Name | Description |
---|---|
state | Get the current state |
state_int | Get the integer corresponding to the current state |
Methods
Name | Description |
---|---|
call_par | Check if this parameter needs to be called to be turned into an array; not for the user |
call_pars | Check if any parameters need to be called to be turned into arrays; not for the user |
convert_callable | Method to handle how callable parameters are processed; not for the user |
convert_timepars | Convert time parameters (durations and rates) to scalars |
disp | Return full display of object |
get_state | Return a copy of the state |
init | Calculate the starting seed and create the RNG |
jump | Advance the RNG, e.g. to timestep “to”, by jumping |
jump_dt | Automatically jump on the next value of dt |
link_module | Shortcut for linking the module |
link_sim | Shortcut for linking the sim, only overwriting an existing one if overwrite=True; not for the user |
make_history | Store the current state in history |
make_rvs | Return default random numbers for scalar parameters; not for the user |
mock | Create a distribution using a mock sim for testing purposes |
plot_hist | Plot the current state of the RNG as a histogram |
ppf | Return default random numbers for array parameters; not for the user |
process_dist | Ensure the distribution works; not for the user |
process_pars | Ensure the supplied dist and parameters are valid, and initialize them; not for the user |
process_seed | Obtain the seed offset by hashing the path to this distribution; not for the user |
process_size | Handle an input of either size or UIDs and calculate size, UIDs, and slots; not for the user |
rand | Simple way to get simple random numbers |
randround | Round the values up or down to an integer stochastically; usually called via dist.rvs(round=True) |
reset | Restore state, allowing the same numbers to be resampled |
rvs | Get random variates – use this! |
set | Set (change) the distribution type, or one or more parameters of the distribution |
show_state | Show the state of the object |
shrink | Shrink the size of the module for saving to disk |
sync_pars | Perform any necessary synchronizations or transformations on distribution parameters; not for the user |
to_json | Return a dictionary representation of the Dist |
update_dist_pars | Update SciPy distribution parameters; not for the user |
validate_pars | Check if parameters are valid; only used for non-SciPy distributions |
call_par
distributions.Dist.call_par(key, val, size, uids)
Check if this parameter needs to be called to be turned into an array; not for the user
call_pars
distributions.Dist.call_pars()
Check if any parameters need to be called to be turned into arrays; not for the user
convert_callable
distributions.Dist.convert_callable(parkey, func, size, uids)
Method to handle how callable parameters are processed; not for the user
convert_timepars
distributions.Dist.convert_timepars()
Convert time parameters (durations and rates) to scalars
This function converts time parameters into bare numbers that will be returned by rvs() depending on the timestep of the parent module for this Dist
. The conversion for these types is
- Durations are divided by
dt
(so the result will be a number of timesteps) - Rates are multiplied by
dt
(so the result will be a number of events, or else the equivalent multiplicate value for the timestep)
disp
distributions.Dist.disp()
Return full display of object
get_state
distributions.Dist.get_state()
Return a copy of the state
init
distributions.Dist.init(=None,
trace=None,
seed=None,
module=None,
sim=None,
slots=False,
force )
Calculate the starting seed and create the RNG
Typically this is not invoked by the user, although the user can call it with force=True to initialize a distribution manually independently of a ss.Sim
object (which is equivalent to setting strict=False when creating the dist).
Parameters
Name | Type | Description | Default |
---|---|---|---|
trace | str | the distribution’s location within the sim | None |
seed | int | the base random number seed that other random number seeds will be generated from | None |
module | ss.Module |
the parent module | None |
sim | ss.Sim |
the parent sim | None |
slots | array | the agent slots of the parent sim | None |
force | bool | whether to skip validation (if the dist has already been initialized, and if any inputs are None) | False |
jump
=None, delta=1, force=False) distributions.Dist.jump(to
Advance the RNG, e.g. to timestep “to”, by jumping
jump_dt
=None, force=False) distributions.Dist.jump_dt(ti
Automatically jump on the next value of dt
Parameters
Name | Type | Description | Default |
---|---|---|---|
ti | int | if specified, jump to this timestep (default: current module timestep plus one) | None |
link_module
=None, overwrite=False) distributions.Dist.link_module(module
Shortcut for linking the module
link_sim
=None, overwrite=False) distributions.Dist.link_sim(sim
Shortcut for linking the sim, only overwriting an existing one if overwrite=True; not for the user
make_history
=False) distributions.Dist.make_history(reset
Store the current state in history
make_rvs
distributions.Dist.make_rvs()
Return default random numbers for scalar parameters; not for the user
mock
='mock', **kwargs) distributions.Dist.mock(trace
Create a distribution using a mock sim for testing purposes
Parameters
Name | Type | Description | Default |
---|---|---|---|
trace | str | the “trace” of the distribution (normally, where it would be located in the sim) | 'mock' |
**kwargs | dict | passed to ss.mock_sim() as well as ss.mock_module() (typically time args, e.g. dt) |
{} |
Example:
dist = ss.normal(3, 2, unit='years').mock(dt=ss.days(1))
dist.rvs(10)
plot_hist
=1000, bins=None, fig_kw=None, hist_kw=None) distributions.Dist.plot_hist(n
Plot the current state of the RNG as a histogram
ppf
distributions.Dist.ppf(rands)
Return default random numbers for array parameters; not for the user
process_dist
distributions.Dist.process_dist()
Ensure the distribution works; not for the user
process_pars
=True) distributions.Dist.process_pars(call
Ensure the supplied dist and parameters are valid, and initialize them; not for the user
process_seed
=None, seed=None) distributions.Dist.process_seed(trace
Obtain the seed offset by hashing the path to this distribution; not for the user
process_size
=1) distributions.Dist.process_size(n
Handle an input of either size or UIDs and calculate size, UIDs, and slots; not for the user
rand
distributions.Dist.rand(size)
Simple way to get simple random numbers
randround
distributions.Dist.randround(rvs)
Round the values up or down to an integer stochastically; usually called via dist.rvs(round=True)
reset
=0) distributions.Dist.reset(state
Restore state, allowing the same numbers to be resampled
Use 0 for original state, -1 for most recent state.
Example:
dist = ss.random(seed=5).init()
r1 = dist(5)
r2 = dist(5)
dist.reset(-1)
r3 = dist(5)
dist.reset(0)
r4 = dist(5)
assert all(r1 != r2)
assert all(r2 == r3)
assert all(r4 == r1)
rvs
=1, round=False, reset=False) distributions.Dist.rvs(n
Get random variates – use this!
Parameters
Name | Type | Description | Default |
---|---|---|---|
n | int / tuple / arr |
if an int or tuple, return this many random variates; if an array, treat as UIDs | 1 |
round | bool | if True, randomly round up or down based on how close the value is | False |
reset | bool | whether to automatically reset the random number distribution state after being called | False |
set
set(*args, dist=None, **kwargs) distributions.Dist.
Set (change) the distribution type, or one or more parameters of the distribution
show_state
=False) distributions.Dist.show_state(output
Show the state of the object
shrink
distributions.Dist.shrink()
Shrink the size of the module for saving to disk
sync_pars
distributions.Dist.sync_pars()
Perform any necessary synchronizations or transformations on distribution parameters; not for the user
to_json
distributions.Dist.to_json()
Return a dictionary representation of the Dist
update_dist_pars
=None) distributions.Dist.update_dist_pars(pars
Update SciPy distribution parameters; not for the user
validate_pars
distributions.Dist.validate_pars()
Check if parameters are valid; only used for non-SciPy distributions
Dists
self, obj=None, *args, base_seed=None, sim=None) distributions.Dists(
Class for managing a collection of Dist objects
Methods
Name | Description |
---|---|
check_seeds | Check that no two distributions share the same seed |
copy_to_module | Copy the Sim’s Dists object to the specified module |
init | Set the base seed, find and initialize all distributions in an object |
jump | Advance all RNGs, e.g. to call “to”, by jumping |
jump_dt | Advance all RNGs to the next timestep |
reset | Reset each RNG |
check_seeds
distributions.Dists.check_seeds()
Check that no two distributions share the same seed
copy_to_module
distributions.Dists.copy_to_module(module)
Copy the Sim’s Dists object to the specified module
init
=None, base_seed=None, sim=None, force=False) distributions.Dists.init(obj
Set the base seed, find and initialize all distributions in an object
In practice, the object is usually a Sim, but can be anything.
jump
=None, delta=1, force=False) distributions.Dists.jump(to
Advance all RNGs, e.g. to call “to”, by jumping
jump_dt
=None, force=False) distributions.Dists.jump_dt(ti
Advance all RNGs to the next timestep
Parameters
Name | Type | Description | Default |
---|---|---|---|
ti | int | if specified, jump to this timestep (default: current sim timestep) | None |
reset
distributions.Dists.reset()
Reset each RNG
multi_random
self, names, *args, **kwargs) distributions.multi_random(
A class for holding two or more ss.random() distributions, and generating random numbers linked to each of them. Useful for e.g. pairwise transmission probabilities.
See ss.combine_rands() for the manual version; in almost all cases this class should be used instead.
Usage
multi = ss.multi_random(‘source’, ‘target’) rvs = multi.rvs(source_uids, target_uids)
Methods
Name | Description |
---|---|
combine_rvs | Combine inputs into one number |
init | Not usually needed since each dist will handle this automatically; for completeness only |
jump | Not usually needed since each dist will handle this automatically; for completeness only |
reset | Not usually needed since each dist will handle this automatically; for completeness only |
rvs | Get random variates from each of the underlying distributions and combine them efficiently |
combine_rvs
distributions.multi_random.combine_rvs(rvs_list, int_type, int_max)
Combine inputs into one number
init
*args, **kwargs) distributions.multi_random.init(
Not usually needed since each dist will handle this automatically; for completeness only
jump
*args, **kwargs) distributions.multi_random.jump(
Not usually needed since each dist will handle this automatically; for completeness only
reset
*args, **kwargs) distributions.multi_random.reset(
Not usually needed since each dist will handle this automatically; for completeness only
rvs
*args) distributions.multi_random.rvs(
Get random variates from each of the underlying distributions and combine them efficiently
scale_types
distributions.scale_types()
Define how distributions scale
Distributions scale in different ways, such as converting between time units. Some distributions can’t be scaled at all (e.g. ss.beta_dist()
or ss.choice()
). For distributions that can be scaled, some distributions can only be (linearly) scaled before the random numbers are generated (called “predraw”), some can only be scaled after (called “postdraw”), and some can be scaled in either way (“both”).
For example, a normal distribution is “both” since 2Normal(a, b) = Normal(2a, 2b). A Poisson distribution is “predraw” since 2Poisson(λ) ≠ Poisson(2λ), and there is no way to get the correct shape of a different Poisson distribution once the numbers have been drawn. Finally, distributions with unitless shape parameters as well as parameter that can have units (e.g. a gamma distribution with shape and scale parameters) are referred to as “postdraw” since scaling all input parameters is invalid (i.e. 2Gamma(shape, scale) ≠ Gamma(2shape, 2scale)), but they can still be scaled (i.e. 2Gamma(shape, scale) = Gamma(1shape, 2*scale)).
To summarize, options for dist.scaling
are:
- 'postdraw' (after the random numbers are drawn, e.g. `ss.weibull()`)
- 'predraw' (before the draw, e.g. `ss.poisson()`)
- 'both' (either pre or post draw, e.g. `ss.normal()`)
- False (not at all, e.g. `ss.beta_dist()`)
Use ss.distributions.scale_types.show()
to show how each distribution scales with time.
Methods
Name | Description |
---|---|
check_postdraw | Check if the supplied distribution supports post-draw (results) scaling |
check_predraw | Check if the supplied distribution supports pre-draw (parameter) scaling |
show | Show which distributions have which scale types |
check_postdraw
distributions.scale_types.check_postdraw(dist)
Check if the supplied distribution supports post-draw (results) scaling
check_predraw
distributions.scale_types.check_predraw(dist)
Check if the supplied distribution supports pre-draw (parameter) scaling
show
=False) distributions.scale_types.show(to_df
Show which distributions have which scale types
Functions
Name | Description |
---|---|
link_dists | Link distributions to the sim and the module; used in module.init() and people.init() |
make_dist | Make a distribution from a dictionary |
link_dists
distributions.link_dists(
obj,
sim,=None,
module=False,
overwrite=False,
init**kwargs,
)
Link distributions to the sim and the module; used in module.init() and people.init()
make_dist
=None, **kwargs) distributions.make_dist(pars
Make a distribution from a dictionary