Metadata-Version: 2.4
Name: pymargins
Version: 0.0.1
Summary: Expert-mode marginal effects for Python with session-level analytical pre-commitment.
Project-URL: Homepage, https://github.com/huntermills707/pymargins
Project-URL: Documentation, https://pymargins.readthedocs.io
Project-URL: Repository, https://github.com/huntermills707/pymargins
Author: Hunter Mills
License: MIT
License-File: LICENSE
Classifier: Development Status :: 2 - Pre-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
Requires-Python: >=3.10
Requires-Dist: jax>=0.4.20
Requires-Dist: jaxlib>=0.4.20
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: scipy>=1.10
Requires-Dist: threadpoolctl>=3.0
Provides-Extra: docs
Requires-Dist: joblib>=1.0; extra == 'docs'
Requires-Dist: lifelines>=0.30; extra == 'docs'
Requires-Dist: linearmodels>=5.0; extra == 'docs'
Requires-Dist: matplotlib>=3.5; extra == 'docs'
Requires-Dist: myst-nb>=1.0; extra == 'docs'
Requires-Dist: openpyxl>=3.0; extra == 'docs'
Requires-Dist: patsy>=0.5; extra == 'docs'
Requires-Dist: polars>=1.0; extra == 'docs'
Requires-Dist: pyarrow>=10.0; extra == 'docs'
Requires-Dist: pysmatch>=2.1; extra == 'docs'
Requires-Dist: scikit-learn>=1.3; extra == 'docs'
Requires-Dist: sphinx-design>=0.5; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Requires-Dist: statsmodels>=0.14; extra == 'docs'
Provides-Extra: lifelines
Requires-Dist: lifelines>=0.30; extra == 'lifelines'
Provides-Extra: linearmodels
Requires-Dist: linearmodels>=5.0; extra == 'linearmodels'
Provides-Extra: matching
Requires-Dist: pysmatch>=2.1; extra == 'matching'
Provides-Extra: polars
Requires-Dist: polars>=1.0; extra == 'polars'
Requires-Dist: pyarrow>=10.0; extra == 'polars'
Provides-Extra: sklearn
Requires-Dist: scikit-learn>=1.3; extra == 'sklearn'
Provides-Extra: statsmodels
Requires-Dist: patsy>=0.5; extra == 'statsmodels'
Requires-Dist: statsmodels>=0.14; extra == 'statsmodels'
Provides-Extra: test
Requires-Dist: hypothesis; extra == 'test'
Requires-Dist: polars>=1.0; extra == 'test'
Requires-Dist: pyarrow>=10.0; extra == 'test'
Requires-Dist: pysmatch>=2.1; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# pymargins

Expert-mode marginal effects for Python. Session-level analytical
pre-commitment, JAX-native autodiff, κ-driven simulation fallback.

## Status

Alpha. End-to-end usable with statsmodels GLM and OLS/WLS/GLS through
auto-detection. Additional adapters (sklearn, linearmodels, mixed
models), cluster/block bootstrap, and reporting polish remain on the
roadmap.

## Quick example

```python
import statsmodels.formula.api as smf
import statsmodels.api as sm
from pymargins import Margins

# Fit a model
fit = smf.glm(
    "outcome ~ treatment + age + sex",
    data=df,
    family=sm.families.Binomial(),
).fit()

# Wrap in a session, committing to log-scale analysis
m = Margins.log_scale(fit, vcov="HC3", level=0.95)
print(m.summary())  # methods-section paragraph

# Pre-flight diagnostic: is delta reliable here?
print(m.diagnose().summary())

# Compute a relative risk contrast
rr = m.contrasts(
    scenarios=[
        {"atexog": {"treatment": 1}, "label": "treated"},
        {"atexog": {"treatment": 0}, "label": "control"},
    ],
    contrasts=[+1, -1],
)
print(rr.summary())  # estimate, asymmetric CI, κ, etc.
```

## Performance notes

- **Bootstrap with `n_jobs > 1`**: Parallel bootstrap uses a
  `ThreadPoolExecutor` for model refitting, but JAX evaluation is
  always serial in the main thread. This avoids XLA compilation race
  conditions. BLAS threads are limited to 1 per worker to prevent
  oversubscription.

- **Large scenario grids**: `expand_scenario` creates one block of rows
  per grid point. For a 10-point grid over a 1M-row dataset this
  materialises 10M rows. Use smaller representative samples (e.g.
  `at="typical"`) or pass explicit `data=` overrides when exploring
  high-dimensional counterfactuals.

- **Memory retention**: `MarginsResult` objects hold references to the
  parent session, design matrices, and gradients. Call
  `result.materialize()` promptly on results you intend to store
  long-term; this drops the heavy machinery while preserving estimates,
  standard errors, and confidence intervals.

## License

MIT
