Algebra
Named-variable distributions multiply and divide according to the chain rule. The free/given metadata on each operand determines the result.
Throughout, start from named xor:
In [1]: from dit import Distribution
In [2]: d = Distribution(['000', '011', '101', '110'], [1/4]*4)
In [3]: d.set_rv_names('XYZ')
Marginal and condition
marginal() keeps the listed free variables;
marginalize() drops them. Both accept positional names
or a single list:
In [4]: d.marginal('X', 'Y')
Out[4]: <Distribution p(X,Y)>
In [5]: d.marginalize('X', 'Y')
Out[5]: <Distribution p(Z)>
Native condition_on() takes positional variable names and
returns a single conditional distribution:
In [6]: p_z_xy = d.condition_on('X', 'Y')
In [7]: p_z_xy
Out[7]: <Distribution p(Z|X,Y)>
In [8]: p_z_xy.is_conditional()
Out[8]: True
Multiplication (chain rule)
Multiplying a marginal by a compatible conditional reconstructs the joint:
In [9]: p_xy = d.marginal('X', 'Y')
In [10]: rebuilt = p_xy * p_z_xy
In [11]: rebuilt
Out[11]: <Distribution p(X,Y,Z)>
In [12]: rebuilt.is_approx_equal(d)
Out[12]: True
Partial application leaves unmatched given variables given:
In [13]: d.marginal('X') * p_z_xy
Out[13]: <Distribution p(X,Z|Y)>
The free variables of the two operands must be disjoint.
Distribution.from_factors() is the named constructor for the same
product.
Division (conditioning)
Dividing a joint by a marginal conditions on the marginal’s free variables:
In [14]: p_xy / d.marginal('X')
Out[14]: <Distribution p(Y|X)>
Numeric-outcome * is different
On unnamed one-dimensional numeric distributions, +, *, %, and
friends transform outcomes (two dice, scaling a die, …). See
Numeric Outcomes. Named-variable * is always the chain rule.
Compatibility condition_on
Passing a list, or the crvs / rvs keywords, uses the older
dit-compatible return format (marginal, list_of_slices) — one
distribution per outcome of the conditioning variables. Prefer the native
form above; the tuple form is still used by some algorithms.
In [15]: marg, cdists = d.condition_on(['X', 'Y'], rvs=['Z'])
In [16]: marg
Out[16]: <Distribution p(X,Y)>
In [17]: len(cdists)
Out[17]: 4
API
- Distribution.marginal(*args)[source]
Marginalise to keep only the specified free variables.
Given (conditioned) variables are always kept.
Supports two call signatures:
marginal('X', 'Y')– positional variable namesmarginal(['X', 'Y'])– list of names (or integer indices)
- Parameters:
*args (str, or a single list/tuple) – The free variable names to keep. Integer indices are auto-resolved to dimension names.
- Returns:
result
- Return type:
Distribution
- Distribution.marginalize(*args)[source]
Marginalise out (remove) the specified free variables.
Supports two call signatures:
marginalize('X')– positional variable namesmarginalize(['X'])– list of names (or integer indices)
- Parameters:
*args (str, or a single list/tuple) – The free variable names to remove.
- Returns:
result
- Return type:
Distribution
- Distribution.condition_on(*cond_vars, rvs=None, crvs=None)[source]
Condition on the specified free variables.
Supports two call signatures:
Native:
condition_on('X', 'Y')– positional var names. Returns a single conditionalDistribution.dit-compat: any of these forms triggers the dit-compatible return format
(marginal, list_of_conditionals):condition_on(crvs=['X'], rvs=['Y'])condition_on(['X'], rvs=['Y'])(positional crvs)condition_on(crvs=['X'])
The returned list contains one
Distributionper outcome of the conditioning variable.
- Parameters:
*cond_vars (str, or a single list/tuple) – Variable names to condition on. If a single list/tuple is passed and
rvsis provided, it is interpreted ascrvs(dit-compat positional form).rvs (list, optional) – Variables to keep in the conditional (dit-compat API).
crvs (list, optional) – Variables to condition on (dit-compat API).
- Returns:
result – A single conditional distribution (native), or a
(marginal, list_of_Distributions)tuple (dit-compat).- Return type:
Distribution or tuple
Examples
>>> p_xyz.condition_on('Z') # native: returns p(X,Y|Z) >>> p_xyz.condition_on('X', 'Y') # native: returns p(Z|X,Y) >>> marg, cdists = p_xyz.condition_on(crvs=['Z']) # dit-compat >>> marg, cdists = p_xyz.condition_on(['Z'], rvs=['X']) # dit-compat
- Distribution.coalesce(rvs, extract=False)[source]
Return a new distribution after coalescing random variables.
Each inner sequence in rvs defines one new random variable as a combination of original variables. The result is a joint
Distributionoverlen(rvs)new random variables whose outcomes are tuples (or the inner values whenextract=Truewith a single group).- Parameters:
rvs (sequence of sequences) – Each inner sequence contains variable names (or integer indices).
extract (bool) – If
Trueandlen(rvs) == 1, the single group’s values are used directly as outcomes instead of being wrapped in 1-tuples.
- Returns:
d
- Return type:
Distribution