Metadata-Version: 2.4
Name: longmi
Version: 0.2.0a1
Summary: Multiple imputation for incomplete longitudinal outcomes with explicit validity conditions
Project-URL: Homepage, https://github.com/aaronjdanielson/longmi
Project-URL: Repository, https://github.com/aaronjdanielson/longmi
Project-URL: Documentation, https://aaronjdanielson.github.io/longmi/
Project-URL: Issues, https://github.com/aaronjdanielson/longmi/issues
Project-URL: Changelog, https://github.com/aaronjdanielson/longmi/blob/main/RELEASE_NOTES.md
Author-email: Aaron Danielson <aaronjdanielson@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Aaron Danielson
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: scipy>=1.10
Provides-Extra: analysis
Requires-Dist: statsmodels>=0.14; extra == 'analysis'
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: statsmodels>=0.14; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs>=1.5; extra == 'docs'
Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
Description-Content-Type: text/markdown

# longmi

longmi creates multiple plausible versions of missing repeated outcomes,
fits the same analysis to each version, and combines the estimates and
uncertainty using Rubin's rules.

It is designed for one incomplete longitudinal outcome and makes the
assumptions behind every result explicit — as part of the result object,
not only in a paper.

```text
Incomplete longitudinal data
            ↓
Fit an imputation model
            ↓
Generate M completed datasets
            ↓
Fit the same analysis M times
            ↓
Pool estimates and uncertainty
            ↓
Report the result and its validity conditions
```

## Installation

```bash
pip install longmi               # core imputation and pooling
pip install "longmi[analysis]"   # plus the statsmodels GEE/GLM adapters
```

The quickstart below uses the `analysis` extra. From a checkout for
development: `pip install -e ".[dev]"`.

## Quickstart

```python
from longmi import LongitudinalData, pool_rubin
from longmi.analysis import StatsmodelsGEE
from longmi.impute import NegativeBinomialImputer

data = LongitudinalData(
    frame,                        # long format, NaN where the outcome is missing
    id_col="subject",
    time_col="period",
    outcome_col="seizures",
    predictor_cols=("treatment", "baseline_seizures", "age"),
    outcome_type="count",
    times=(1, 2, 3, 4),           # declared design grid
)

# treatment-by-wave terms keep the analysis's interaction represented
# in the imputation model (assumption A8)
imputer = NegativeBinomialImputer(time_interactions=("treatment",))

fit = imputer.fit(data)           # validate, estimate, diagnose once
completed = fit.impute(m=50, random_state=20260723)

analysis = StatsmodelsGEE(
    "seizures ~ treatment * period + baseline_seizures + age",
    groups="subject",
    family="poisson",
    cov_struct="exchangeable",
)

result = pool_rubin(completed.analyze(analysis), validity=completed.declaration)
print(result.summary())
print(result.validity_report())
```

The same fitted model reruns under a missing-not-at-random scenario:

```python
from longmi import DeltaAdjustment
import numpy as np

shifted = fit.impute(m=50, random_state=20260723,
                     delta=DeltaAdjustment(np.log(0.8)))  # means x 0.8
```

## What is implemented

- **Data contract** — `LongitudinalData` validates the participant-wave
  grid, preserves observed outcomes bit-for-bit through completion, and
  enforces count support ([src/longmi/data.py](https://github.com/aaronjdanielson/longmi/blob/main/src/longmi/data.py)).
- **Imputers** — `JointGaussianImputer` (continuous outcomes; exact
  conjugate data augmentation, wave-saturated mean, unstructured
  covariance) and `NegativeBinomialImputer` (longitudinal counts; NB
  random intercept, Gauss–Hermite ML with verified convergence,
  large-sample posterior-approximation parameter draws, adaptive-grid
  random-intercept draws, gamma–Poisson outcome draws). Both support
  delta-adjusted MNAR sensitivity analysis and report numerical
  diagnostics; a failed fit refuses to impute.
- **Analyses** — `StatsmodelsGEE` (marginal GEE, robust sandwich,
  verified to reproduce direct statsmodels fits exactly),
  `StatsmodelsGLM`, and `CallableAnalysis` for custom estimators.
- **Pooling** — `pool_rubin`, multivariate, bit-compatible with
  `mice::pool.scalar` (verified at 1e-12 against R), Barnard–Rubin
  degrees of freedom, fraction of missing information, and
  `validity_report()` distinguishing verified properties from declared
  assumptions.

## Validation status

Deterministic components are cross-validated against R (`mice`);
imputation backends have unit, invariant, and numerical-diagnostic tests
plus a seeded simulation suite for bias and confidence-interval coverage
(`pytest -m slow tests/simulation`). See
[docs/project-status.md](https://github.com/aaronjdanielson/longmi/blob/main/docs/project-status.md) for the canonical
per-feature maturity table — the backends are not claimed statistically
validated beyond what that table states.

## Documentation

- [docs/index.md](https://github.com/aaronjdanielson/longmi/blob/main/docs/index.md) — documentation home (build with
  `mkdocs serve` after `pip install -e ".[docs]"`);
- [Why impute the response?](https://github.com/aaronjdanielson/longmi/blob/main/docs/explanation/why_impute_the_response.md)
  and [MCAR, MAR, MNAR](https://github.com/aaronjdanielson/longmi/blob/main/docs/explanation/mcar_mar_mnar.md) — concepts;
- [Choosing an imputer](https://github.com/aaronjdanielson/longmi/blob/main/docs/how_to/choose_an_imputer.md),
  [interpreting diagnostics](https://github.com/aaronjdanielson/longmi/blob/main/docs/how_to/interpret_diagnostics.md),
  [reporting an analysis](https://github.com/aaronjdanielson/longmi/blob/main/docs/how_to/report_an_analysis.md) — task guides;
- [Mathematical foundations and validity conditions](https://github.com/aaronjdanielson/longmi/blob/main/docs/theory/mathematical_foundations.md),
  [assumptions A1–A8](https://github.com/aaronjdanielson/longmi/blob/main/docs/theory/assumptions.md),
  [GEE after imputation](https://github.com/aaronjdanielson/longmi/blob/main/docs/theory/gee_after_imputation.md) — theory;
- [algorithm specifications](https://github.com/aaronjdanielson/longmi/blob/main/docs/algorithms/) — what the software
  actually computes, approximations included;
- [worked examples](https://github.com/aaronjdanielson/longmi/blob/main/docs/examples/) — the epil count example and the
  external validation oracles.

## Development

```bash
pip install -e ".[dev]"
pytest                       # fast suite
pytest -m slow tests/simulation -q   # simulation studies
Rscript validation/r/rubin_reference.R   # regenerate R pooling reference
```

longmi implements established missing-data theory (Rubin 1976, 1987;
Barnard–Rubin 1999; Meng 1994; Wang–Robins 1998); it does not introduce a
new proof of multiple imputation. See [REFERENCES.md](https://github.com/aaronjdanielson/longmi/blob/main/REFERENCES.md) for
sources and [CITATION.cff](https://github.com/aaronjdanielson/longmi/blob/main/CITATION.cff) to cite the software. MIT
license.
