Skip to content

Repository files navigation

CensoredDistributions.jl CensoredDistributions.jl logo

Documentation Build Status Code Quality License & DOI Downloads
Stable Dev Test codecov SciML Code Style Aqua QA JET License: MIT DOI Downloads Downloads
AD backends ForwardDiff ReverseDiff (tape) Enzyme forward Enzyme reverse Mooncake reverse Mooncake forward
AD cov ForwardDiff cov ReverseDiff cov Enzyme forward cov Enzyme reverse cov Mooncake reverse cov Mooncake forward

Primary event censored distributions for Distributions.jl

Why CensoredDistributions.jl?

  • Fitting observed delays as if they were exact biases the estimate, because the initial event is usually known only to within a window and the longest delays are missing wherever observation stopped.
  • Primary event censoring and interval censoring are each one call on an existing Distributions.jl distribution, and double_interval_censored composes them with right truncation in the order that keeps the likelihood correct, so it does not have to be derived by hand.
  • The result is still a Distributions.jl distribution, so it can be fitted in Turing.jl, or anywhere else that takes a distribution, by Bayesian inference or maximum likelihood.
  • Gamma, lognormal and Weibull delays with a uniform primary event use analytical CDFs, and every other pairing falls back to numerical integration, so the common cases are fast and nothing is left unsupported.
  • Gradients are tested against ForwardDiff, ReverseDiff, Enzyme and Mooncake in CI, so a censored likelihood can be fitted with a gradient-based sampler such as NUTS.

Getting started

For a detailed walkthrough of primary censoring, truncation, interval censoring, and all supported distribution operations (PDF, CDF, quantiles, moments, sampling, fitting), see the Getting Started documentation.

The following example demonstrates how to create a double interval censored distribution (combines primary event, interval censoring, and right truncation (using Distributions.truncated)):

using CensoredDistributions, Distributions
using CairoMakie, AlgebraOfGraphics, DataFramesMeta

CairoMakie.activate!(type = "png", px_per_unit = 2)

# Create a censored distribution accounting for primary and secondary censoring
original = Gamma(2, 3)
censored = double_interval_censored(original; upper = 15, interval = 1)

# Compare the distributions
x = 0:0.01:20
df = vcat(
    DataFrame(x = x, pdf = pdf.(original, x),
        Distribution = "Original Gamma"),
    DataFrame(x = x, pdf = pdf.(censored, x),
        Distribution = "Double Censored and right truncated")
)
draw(
    data(df) *
    mapping(:x, :pdf, color = :Distribution) *
    visual(Lines, linewidth = 2)
)

You can fit censored distributions to data using Turing.jl and any of its supported inference methods. For example, using MCMC for Bayesian inference:

using Turing, StatsBase

# Generate synthetic data from the censored distribution
data = rand(censored, 1000)

# Get counts of unique values for weighted likelihood
values = unique(data)
weights = [count(==(val), data) for val in values]

# Define a Turing model for fitting with weighted likelihood
@model function double_censored_model(values, weights)
    # Priors for Gamma parameters - weakly informative, not centered on true values
    α ~ truncated(Normal(1, 2), 0, Inf)
    θ ~ truncated(Normal(1, 2), 0, Inf)

    # Create the censored distribution
    censored_dist = double_interval_censored(Gamma(α, θ); upper = 15, interval = 1)

    # Vectorized weighted likelihood
    values ~ weight(censored_dist, weights)
end

# Fit using MCMC for Bayesian inference
model = double_censored_model(values, weights)
chain = sample(model, NUTS(), MCMCThreads(), 1000, 2; progress = false)

# Summarise the posterior
summarystats(chain)

Or fit using MAP:

map_result = maximum_a_posteriori(model)

Relationship to Distributions.jl

Both CensoredDistributions.jl and Distributions.jl's built-in censored() function handle censoring, but they address different types of uncertainty:

Aspect Distributions.jl censored() CensoredDistributions.jl
Type Observation censoring Event timing censoring
Question "Can't measure outside bounds?" "Don't know exactly when it happened?"
Example Lab test detection limits Disease onset within time window
Use case Measurement limitations Epidemiological modeling

These approaches complement each other - you can apply observation limits to distributions with event timing uncertainty when both types of censoring affect your data.

CensoredDistributions.jl also works well with truncated() from Distributions.jl and supports both primary event censoring (initial event timing uncertainty) and secondary event censoring (observation window effects).

Related packages

  • ComposedDistributions.jl is the general composition layer split out of this package, building event trees from chains, branches and competing outcomes, with a censored delay usable as one leaf.
  • ConvolvedDistributions.jl convolves independent delays into sums, differences and products, and its convolve_series deliberately leaves discretisation to this package rather than binning a continuous delay itself.
  • ModifiedDistributions.jl rescales, weights and hazard-modifies a distribution, and those modifiers wrap a censored distribution the same way they wrap any other.

Where to learn more

Supporting and citing

If you would like to help support CensoredDistributions.jl, please star the repository as such metrics may help us secure funding in the future.

If you use CensoredDistributions.jl in your work, please cite it:

@software{CensoredDistributions_jl,
  author       = {Abbott, Sam and Bayer, Damon and Brand, Sam and DeWitt, Michael and Lemaitre, Joseph},
  title        = {CensoredDistributions.jl},
  year         = {2025},
  doi          = {10.5281/zenodo.18474652},
  url          = {https://github.com/EpiAware/CensoredDistributions.jl}
}

Contributing

We welcome contributions and new contributors! We particularly appreciate help on identifying and identified issues. Please check and add to the issues, and/or add a pull request and see our developer documentation for more information.

Code of conduct

Please note that the CensoredDistributions project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

About

Additional censored event tools for Distributions.jl

Resources

Code of conduct

Contributing

Security policy

Stars

15 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages