lnccbrown / lnccbrown/HSSM

Regression priors are generated for fixed offset() terms and explicit offset priors are silently ignored

Open
#1,234 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
124
Forks
24
Avg merge
19h 32m
Merged PRs (30d)
60

Description

## Summary

HSSM generates and displays regression priors for `offset()` terms even though Formulae/Bambi define an offset as a fixed addition with coefficient one. Exact user priors for offsets are likewise retained in HSSM's prior dictionary but silently ignored when Bambi builds the model.

The likelihood contribution is correct; model reporting and explicit-prior handling are not.

This was reproduced against HSSM `main` at `5e8610b9`, Bambi 0.20, and Bambi current `main`.

## Reproducer

```python
model = hssm.HSSM(
data=data,
include=[{"name": "v", "formula": "v ~ 1 + offset(exposure)"}],
prior_settings="safe",
)

model.params["v"].prior["offset(exposure)"]
# Normal(mu=0, sigma=0.25)

model.model.components["v"].terms["offset(exposure)"].prior
# 1
```

No coefficient random variable is created. If an exact prior such as `Normal(10, 1)` is supplied for `offset(exposure)`, HSSM displays it but Bambi still fixes the coefficient to one.

## Root cause

HSSM's safe-prior loop treats every non-HSGP, non-intercept common Formulae term as an estimated coefficient. It does not special-case `term.kind == "offset"`.

Bambi intentionally:

- constructs an `OffsetTerm` with prior `1`;
- skips offsets during prior construction/update;
- adds the offset column directly to the linear predictor.

Thus generated and exact offset priors can never affect the graph.

## Expected behavior

- HSSM should not generate a prior for an offset.
- An exact explicit prior key for an offset should fail early with an explanation instead of being silently discarded.
- A `"common"` wildcard should remain valid for ordinary common terms and should not be rejected merely because the formula also contains an offset.
- Bambi's fixed coefficient-one offset contribution must remain unchanged.

## Proposed commit plan

This work should start after #1227 because it uses the always-run Formulae metadata preparation introduced there.

### 1. `refactor: cache fixed Formulae offset terms (#1234)`

- Extend `RegressionParam`'s prepared metadata with exact offset-term names.
- Cache strings only; do not retain Formulae objects or matrices.
- Preserve the existing public/private `terms` behavior.
- Test one offset, multiple offsets, transformed offset expressions, RHS-only formula shorthand, and formulas mixing offsets with ordinary/HSGP/group terms.

### 2. `fix: exclude fixed offsets from regression priors (#1234)`

- Skip offset terms during safe-prior generation, analogous to the HSGP special case.
- Validate exact user prior keys for offsets under both `prior_settings="safe"` and `None`.
- Raise an actionable error explaining that `offset(x)` has coefficient one and that an estimated coefficient should be written as an ordinary term.
- Preserve exact-over-wildcard precedence for ordinary terms and do not reject the `"common"` wildcard.
- Assert that Bambi still stores prior `1`, creates no offset coefficient RV, and preserves the raw offset contribution in predictions.

### 3. `docs: document fixed offset semantics (#1234)`

- Explain that offsets are fixed additions on the linear-predictor scale.
- Contrast `offset(exposure)` with an estimated `exposure` coefficient.
- Add an Unreleased changelog entry.
- Note a possible Bambi follow-up to reject exact offset priors upstream as well.

## Acceptance criteria

- Safe HSSM prior dictionaries contain no offset keys.
- Exact offset priors fail early under both prior modes.
- Bambi retains coefficient one and no offset free RV appears.
- Ordinary exact/common-wildcard priors and HSGP handling remain unchanged.
- Predictions retain the offset contribution exactly.
- Focused Formulae/model-structure tests, the non-slow suite, Ruff, Pyrefly, mypy, and strict docs pass.

## Related work

- #1227 provides the structural metadata path this fix should extend.
- Closed #851 concerns non-centered latent variables named `*_offset` and is unrelated to formula offsets.

Contributor guide

Open the contributing guide

Research direction

Start with RegressionParam's prepared Formulae metadata and the safe-prior loop described in the issue; trace how offset terms and exact or wildcard prior keys are handled. Extend the metadata and prior validation while preserving Bambi's coefficient-one offset behavior, then run the focused Formulae/model-structure tests and the non-slow suite. Update the documentation and Unreleased changelog, and verify Ruff, Pyrefly, mypy, and strict docs checks pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.