Getting started
Welcome to the ModifiedDistributions documentation. This page is the quickstart: what the package is for, how to install it, and a tour of each modifier.
ModifiedDistributions provides modifiers for Distributions.jl univariate distributions. A modifier is a wrapper around exactly one distribution that changes one behaviour, returning something that still works anywhere a distribution is expected. Modifiers nest freely, and the get_dist protocol unwraps them again.
Installation
using Pkg
Pkg.add("ModifiedDistributions")See the Installation page for more detail.
Load the package alongside Distributions.jl:
using ModifiedDistributions, DistributionsAffine transforms
affine gives the exact change-of-variables distribution of Y = scale * X + shift:
d = affine(LogNormal(1.5, 0.5); scale = 2.0, shift = 1.0)
(mean = mean(d), logpdf = logpdf(d, 5.0), median = quantile(d, 0.5))(mean = 11.156838074360163, logpdf = -2.914108658241349, median = 9.963378140676129)The full distribution interface works, including sampling and ccdf/logccdf computed directly rather than via 1 - cdf, so upper-tail probabilities stay precise.
Likelihood weights
weight scales the logpdf contribution of an observation, which is the standard trick for aggregated or count data. The two numbers printed below match, showing the weighted log-density is exactly 25 times the base:
base = Normal(2.0, 1.0)
wd = weight(base, 25) # an observation seen 25 times
(weighted = logpdf(wd, 3.5), manual = 25 * logpdf(base, 3.5))(weighted = -51.098463330116815, manual = -51.098463330116815)Weights can also arrive at observation time, or vectorised as a Product distribution:
wd_obs = weight(base) # weight supplied with the observation
logpdf(wd_obs, (value = 3.5, weight = 25))-51.098463330116815wds = weight(base, [3, 1, 4])
logpdf(wds, [1.9, 2.1, 2.3])-7.551508265637382Everything other than logpdf (sampling, cdf, quantiles, summary statistics) delegates to the underlying distribution, so a weighted distribution stays a complete generative object in a probabilistic programming model.
Forward-series transforms
thin and cumulative attach a deterministic operation intended for a downstream count series (for example, one produced by a convolution layer): thinning by an ascertainment probability, or accumulating to cumulative incidence. They are transparent to every distribution method, so the two log-densities printed below are identical:
td = thin(Gamma(2.0, 1.0), 0.3)
(thinned = logpdf(td, 2.0), base = logpdf(Gamma(2.0, 1.0), 2.0))(thinned = -1.3068528194400546, base = -1.3068528194400546)The generic series_transform accepts any callable series -> series as an escape hatch. thin and cumulative cover the common cases; series_transform takes any callable series -> series.
Hazard modification
modify changes a continuous distribution's hazard function through a link. Under proportional hazards the survival function is raised to the power exp(effect), and the two values printed below agree:
base = Weibull(1.5, 2.0)
md = modify(base, 0.5) # proportional hazards: h*(t) = exp(0.5) * h(t)
(modified = ccdf(md, 1.0), base_power = ccdf(base, 1.0)^exp(0.5))(modified = 0.5582708749558248, base_power = 0.558270874955825)The default log link gives proportional hazards; link = identity gives additive hazards for non-negative effects.
Unwrapping
Modifiers nest, and get_dist / get_dist_recursive peel them back off:
nested = weight(affine(Normal(0, 1); scale = 2.0), 3.0)
(get_dist(nested), get_dist_recursive(nested))(Affine(Distributions.Normal{Float64}(μ=0.0, σ=1.0)), Distributions.Normal{Float64}(μ=0.0, σ=1.0))Downstream packages can extend get_dist for their own wrappers to join the same protocol.
Extensions
Loading ComposedDistributions.jl alongside this package activates an extension that lets the modifier verbs apply to a composed Sequential chain. A chain observes one scalar quantity, its convolved total, so a modifier on the chain modifies that observed scalar:
using ModifiedDistributions, ComposedDistributions, Distributions
chain = sequential(:onset_admit => Gamma(2.0, 1.0),
:admit_death => LogNormal(0.5, 0.4))
wd = weight(chain, 3.0) # weights the chain's observed total
logpdf(wd, 5.0) # 3 times the log-density of the observed totalThe extension in this package handles applying modifiers to a chain; the reverse direction — rewrapping modifier leaves inside a chain — lives in ComposedDistributions.jl. See the Modifiers across composed chains tutorial for a worked example.
Learning more
Want the full interface? See the Public API.
Common questions are answered in the FAQ.
Writing your own wrapper? See Writing a new modifier.
Want to report a problem or ask a question? Open an issue or start a discussion on the GitHub repository.