Skip to content

feat(continuous): add a zero-one-inflated beta family - #55

Merged
aaronstevenwhite merged 1 commit into
mainfrom
feat/zero-one-inflated-beta
Jul 22, 2026
Merged

feat(continuous): add a zero-one-inflated beta family#55
aaronstevenwhite merged 1 commit into
mainfrom
feat/zero-one-inflated-beta

Conversation

@aaronstevenwhite

Copy link
Copy Markdown
Contributor

Summary

Adds a zero-one-inflated beta likelihood so proportion data with exact zeros and exact ones can be modelled directly, rather than nudged inward or dropped.

Motivation

Rates, shares, and probabilities are routinely recorded with observations sitting exactly on 0 or 1. A beta likelihood cannot represent them: its density vanishes at both endpoints. The usual workarounds either perturb the data or discard the boundary cases, both of which change the inference. A zero-one-inflated beta puts explicit point masses at the endpoints and keeps a beta on the interior.

Changes

  • continuous/: ZeroOneInflatedBeta(mu, phi, zoi, coi) mixes point masses at 0 and 1 with a beta on the open interval, so P(0) = zoi (1 - coi), P(1) = zoi coi, and the remaining mass carries Beta(mu phi, (1 - mu) phi). The continuous part uses the mean-precision parameterisation, leaving mu the mean of the beta component and phi its precision. A ConditionalZeroOneInflatedBeta accompanies it for [role=kernel] declarations.
  • dsl/compiler/: the family registers in the prelude as ZeroOneInflatedBeta, and the inline observe ... <- ZeroOneInflatedBeta(...) surface is wired.
  • formulas/: the formula frontend names it zero_one_inflated_beta, with a logit link on the mean and on both inflation probabilities and a log link on the precision.

API impact

  • Additive only (new symbols, no existing behaviour changed).

Tests

  • New tests added for new behaviour: four cases in tests/test_zip_hurdle_mixture.py covering the two endpoint masses against their closed forms, the interior density against a scaled beta, normalisation (the masses plus the integral over the open interval sum to 1), and batch broadcasting. The registry test now also asserts ZeroOneInflatedBeta is present.
  • ruff check and ruff format --check pass.
  • pyright reports 0 errors on the changed modules.
  • tests/test_zip_hurdle_mixture.py passes (13 tests); the formula / family / registry selection passes (233 tests).
  • Full pytest -x not run on this branch.

Documentation

  • Docstrings on the new distribution describe the parameterisation and cite the source (Ospina & Ferrari 2010 / brms ZOIB).
  • CHANGELOG.md and docs/developer/changelog.md carry a 0.17.0 entry.
  • No user-facing page under docs/ added for the family.

Checklist

  • Commits are focused and have descriptive messages.
  • No backward-compatibility shims added.
  • Comments describe the code as it stands.
  • No secrets, credentials, or large binary artefacts in the diff.

Note on versioning

pyproject.toml is bumped 0.16.0 -> 0.17.0 for the additive family. Worth a look: the transpile line of work carries its own 0.17.0.dev0, so whoever cuts the release should confirm both land under the same number.

Proportion data is frequently recorded with exact zeros and exact ones,
which a beta likelihood cannot represent: its density vanishes at both
endpoints, so boundary observations have to be nudged inward or dropped.

`ZeroOneInflatedBeta(mu, phi, zoi, coi)` mixes point masses at 0 and 1
with a beta on the open interval. `zoi` is the probability that an
observation sits at an endpoint and `coi` the probability that such an
endpoint is 1, so `P(0) = zoi (1 - coi)`, `P(1) = zoi coi`, and the
remaining mass carries `Beta(mu phi, (1 - mu) phi)`. The continuous part
uses the mean-precision parameterisation, leaving `mu` the mean of the
beta component and `phi` its precision.

The family registers in the compiler prelude as `ZeroOneInflatedBeta`
and in the formula frontend as `zero_one_inflated_beta`, with a logit
link on the mean and on both inflation probabilities and a log link on
the precision.
@aaronstevenwhite
aaronstevenwhite merged commit 3245edd into main Jul 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant