bossanova 0.1.0.dev18__tar.gz → 0.1.0.dev20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/.gitignore +2 -1
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/PKG-INFO +1 -1
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/__init__.py +4 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/__init__.py +18 -2
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/expressions.py +11 -11
- bossanova-0.1.0.dev20/bossanova/internal/compare/__init__.py +12 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/display.py +44 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/design/__init__.py +0 -6
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/__init__.py +0 -23
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/dispatch.py +4 -4
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/glmer.py +18 -21
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/__init__.py +0 -19
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/__init__.py +0 -23
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/dispatch.py +9 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/__init__.py +2 -13
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/slopes.py +15 -0
- bossanova-0.1.0.dev20/bossanova/internal/rendering/__init__.py +22 -0
- bossanova-0.1.0.dev20/bossanova/internal/rendering/markdown.py +163 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/__init__.py +0 -12
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/mem.py +4 -5
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/predict.py +14 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/model/core.py +230 -183
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/model/result.py +84 -0
- bossanova-0.1.0.dev20/bossanova/model/summary.py +1103 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/pyproject.toml +10 -2
- bossanova-0.1.0.dev18/bossanova/internal/compare/__init__.py +0 -27
- bossanova-0.1.0.dev18/bossanova/internal/rendering/__init__.py +0 -16
- bossanova-0.1.0.dev18/bossanova/model/summary.py +0 -467
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/LICENSE +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/README.md +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/README.md +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/advertising.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/cake.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/chickweight.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/credit.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/gammas.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/mtcars.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/penguins.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/poker.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/sleep.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/titanic.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/titanic_test.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/data/titanic_train.csv +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/distributions/continuous.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/distributions/discrete.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/distributions/varying.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/compare.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/cv.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/deviance.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/f_test.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/helpers.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/ic.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/lrt.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/lrt_compare.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/compare/refit.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/dataframes.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/resamples.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/results.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/specs.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/builders/state.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/schemas.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/data.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/explore.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/formula.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/specs.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/state.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/validators.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/design/coding.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/design/names.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/design/reference.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/design/z_matrix.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/convergence.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/diagnostics.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/glm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/lmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/ols.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/predict.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/rank.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/fit/varying.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/bundle.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/contrast_registry.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/contrast_specs.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/design.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/encoding.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/evaluate.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/evaluate_contrast.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/evaluate_newdata.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/evaluate_transforms.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/helpers.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parse.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parser/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parser/expr.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parser/parser.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parser/scanner.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/parser/token.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/formula/random_effects.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/asymptotic.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/bootstrap.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/cv.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/formula_utils.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/mee.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/params.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/permutation.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/prediction.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/profile.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/common.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/core.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/glmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/lm_operators.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/lmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/results.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample/simulate.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/resample_bundle.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/satterthwaite_emm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/infer/simulation.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/bracket_contrasts.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/compute.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/conditions.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/contrasts.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/emm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/explore.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/explore_parser.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/explore_scanner.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/factors.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/grid.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/inference.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/joint_tests.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/matrices.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/transforms.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/marginal/validation.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/backend/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/backend/dispatch.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/backend/jax.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/backend/numpy.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/backend/protocol.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/batching.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/config.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/convergence.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/differentiation.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/algebra.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/base.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/core.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/derived.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/factories.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/plotting.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/distributions/probability.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/binomial.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/create.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/gamma.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/gaussian.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/links.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/poisson.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/response.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/schema.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/family/tdist.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/diagnostics.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/estimation.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/hypothesis.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/information_criteria.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/multiplicity.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/profile.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/sandwich.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/satterthwaite.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/wald_variance.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/inference/welch.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/linalg/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/linalg/qr.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/linalg/schur.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/linalg/sparse.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/linalg/svd.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/predict.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/rng.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/rounding.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/glm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/glmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/heuristics.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/initialization.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/lambda_builder.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/lambda_sparse.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/lambda_template.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/lmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/optimize.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/pirls_sparse.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/solvers/quadrature.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/tolerances.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/transforms.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/variance.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/maths/weights.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/rendering/latex.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/generate.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/glm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/glmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/lm.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/dgp/lmer.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/harness.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/metrics.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/model_sim.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/simulation/power.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/README.md +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/cognition.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/compare.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/core.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/core_data.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/core_protocols.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/core_sizing.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/core_viz.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/dag.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/design.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/fit.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/fit_builders.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/fit_layers.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/helpers.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/lattice.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/layout.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/mem_forest.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/params.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/profile.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/ranef.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/relationships.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/resamples.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/resid.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/viz/vif.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/model/__init__.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/model/guards.py +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/py.typed +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/tests/bossanova_benchmarks/bootstrap/data/README.md +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/tests/bossanova_benchmarks/insteval/data/README.md +0 -0
- {bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/tests/bossanova_tests/hypothesis/README.md +0 -0
|
@@ -17,7 +17,7 @@ docs/_build/
|
|
|
17
17
|
docs/performance/
|
|
18
18
|
profile_*.py
|
|
19
19
|
benchmarks/
|
|
20
|
-
!bossanova-docs/
|
|
20
|
+
!bossanova-docs/benchmarking/
|
|
21
21
|
examples/
|
|
22
22
|
papers/
|
|
23
23
|
paper-summaries/
|
|
@@ -84,3 +84,4 @@ bossanova-docs/wip/
|
|
|
84
84
|
research.md
|
|
85
85
|
201b-ghct-05-models/
|
|
86
86
|
emmeans/
|
|
87
|
+
walkthrough.md
|
|
@@ -36,6 +36,9 @@ from bossanova.internal.compare import compare, lrt # noqa: E402
|
|
|
36
36
|
# Visualization
|
|
37
37
|
from bossanova.internal import viz # noqa: E402
|
|
38
38
|
|
|
39
|
+
# Export utilities
|
|
40
|
+
from bossanova.internal.rendering.markdown import to_markdown # noqa: E402
|
|
41
|
+
|
|
39
42
|
# Expressions
|
|
40
43
|
from bossanova import expressions # noqa: E402
|
|
41
44
|
|
|
@@ -53,6 +56,7 @@ __all__ = [
|
|
|
53
56
|
"set_display_digits",
|
|
54
57
|
"set_singular_tolerance",
|
|
55
58
|
"show_datasets",
|
|
59
|
+
"to_markdown",
|
|
56
60
|
"viz",
|
|
57
61
|
]
|
|
58
62
|
|
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
"""Bundled sample datasets for regression and mixed-effects modeling.
|
|
1
|
+
"""Bundled sample datasets for regression and mixed-effects modeling.
|
|
2
|
+
|
|
3
|
+
| Dataset | Argument | Description |
|
|
4
|
+
|---------|----------|-------------|
|
|
5
|
+
| Advertising | `"advertising"` | TV, radio, newspaper ad spend vs sales (200 x 4) |
|
|
6
|
+
| Cake | `"cake"` | Baking angle by recipe and temperature (270 x 5) |
|
|
7
|
+
| ChickWeight | `"chickweight"` | Chick weight over time by diet (578 x 4) |
|
|
8
|
+
| Credit | `"credit"` | Credit card balance by income and demographics (400 x 11) |
|
|
9
|
+
| Gammas | `"gammas"` | Simulated BOLD signal for Gamma GLM (6000 x 4) |
|
|
10
|
+
| mtcars | `"mtcars"` | Motor Trend car road tests (32 x 12) |
|
|
11
|
+
| Penguins | `"penguins"` | Palmer Penguins body measurements (344 x 8) |
|
|
12
|
+
| Poker | `"poker"` | Poker hand outcomes by skill and limit (300 x 4) |
|
|
13
|
+
| Sleep | `"sleep"` | Reaction time vs sleep deprivation (180 x 3) |
|
|
14
|
+
| Titanic | `"titanic"` | Passenger survival with demographics (891 x 15) |
|
|
15
|
+
| Titanic Train | `"titanic_train"` | Titanic training set, Kaggle format (891 x 12) |
|
|
16
|
+
| Titanic Test | `"titanic_test"` | Titanic test set, Kaggle format (418 x 11) |
|
|
17
|
+
"""
|
|
2
18
|
|
|
3
19
|
from importlib.resources import files
|
|
4
20
|
from typing import Literal
|
|
@@ -52,7 +68,7 @@ def show_datasets() -> pl.DataFrame:
|
|
|
52
68
|
```python
|
|
53
69
|
from bossanova.data import show_datasets
|
|
54
70
|
show_datasets()
|
|
55
|
-
# shape: (
|
|
71
|
+
# shape: (12, 2)
|
|
56
72
|
# ┌───────────────┬─────────────────────────────────┐
|
|
57
73
|
# │ name ┆ description │
|
|
58
74
|
# │ --- ┆ --- │
|
|
@@ -4,17 +4,17 @@ This module provides stateless Polars expressions for data transformations
|
|
|
4
4
|
commonly used in statistical modeling. These match the semantics of the
|
|
5
5
|
formula-based transforms in `bossanova.internal.formula`.
|
|
6
6
|
|
|
7
|
-
Core Transforms
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Additional Helpers
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
**Core Transforms:**
|
|
8
|
+
- `center(col)` — subtract mean only
|
|
9
|
+
- `norm(col)` — divide by std only
|
|
10
|
+
- `zscore(col)` — traditional z-score (1 SD)
|
|
11
|
+
- `scale(col)` — Gelman scaling (2 SD)
|
|
12
|
+
|
|
13
|
+
**Additional Helpers:**
|
|
14
|
+
- `rank(col, method)` — average-method rank transform
|
|
15
|
+
- `winsorize(col, lower, upper)` — percentile capping
|
|
16
|
+
- `lag(col, n)` — lagged values
|
|
17
|
+
- `lead(col, n)` — lead values
|
|
18
18
|
|
|
19
19
|
The scale() transform follows Gelman (2008) recommendation to divide by
|
|
20
20
|
2 standard deviations, making continuous predictor coefficients directly
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Model comparison: information criteria, likelihood ratio tests, and composite tables.
|
|
2
|
+
|
|
3
|
+
Call chain:
|
|
4
|
+
bossanova.compare(m1, m2, ...) -> compare() (composite AIC/BIC/loglik table)
|
|
5
|
+
bossanova.lrt(m1, m2) -> lrt() (nested model likelihood ratio test)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from bossanova.internal.compare.compare import compare
|
|
9
|
+
from bossanova.internal.compare.ic import compare_aic, compare_bic
|
|
10
|
+
from bossanova.internal.compare.lrt import lrt
|
|
11
|
+
|
|
12
|
+
__all__ = ["compare", "compare_aic", "compare_bic", "lrt"]
|
{bossanova-0.1.0.dev18 → bossanova-0.1.0.dev20}/bossanova/internal/containers/structs/display.py
RENAMED
|
@@ -101,3 +101,47 @@ class MathDisplay:
|
|
|
101
101
|
LaTeX equation without $$ delimiters.
|
|
102
102
|
"""
|
|
103
103
|
return self.equation
|
|
104
|
+
|
|
105
|
+
def to_markdown(
|
|
106
|
+
self,
|
|
107
|
+
path: str | None = None,
|
|
108
|
+
*,
|
|
109
|
+
include_explanations: bool = True,
|
|
110
|
+
) -> str:
|
|
111
|
+
"""Export equation as Quarto-compatible display math markdown.
|
|
112
|
+
|
|
113
|
+
Wraps the equation in ``$$...$$`` display math delimiters. When
|
|
114
|
+
*include_explanations* is True, appends the term explanations as
|
|
115
|
+
a bulleted list below the equation block.
|
|
116
|
+
|
|
117
|
+
Suitable for embedding in ``.qmd`` files via Quarto's
|
|
118
|
+
``{{< include >}}`` shortcode.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
path: Optional file path to write the markdown. Parent
|
|
122
|
+
directories are created automatically. If None, returns
|
|
123
|
+
the string without writing.
|
|
124
|
+
include_explanations: If True (default), append term
|
|
125
|
+
explanations below the equation.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Markdown string with ``$$equation$$`` and optional
|
|
129
|
+
explanations.
|
|
130
|
+
|
|
131
|
+
Examples:
|
|
132
|
+
>>> m.show_math().to_markdown("equations/model_eq.md")
|
|
133
|
+
>>> md = m.show_math().to_markdown(include_explanations=False)
|
|
134
|
+
"""
|
|
135
|
+
from bossanova.internal.rendering.markdown import (
|
|
136
|
+
equation_to_markdown,
|
|
137
|
+
write_text,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
text = equation_to_markdown(
|
|
141
|
+
self.equation,
|
|
142
|
+
self.explanations,
|
|
143
|
+
include_explanations=include_explanations,
|
|
144
|
+
)
|
|
145
|
+
if path is not None:
|
|
146
|
+
write_text(text, path)
|
|
147
|
+
return text
|
|
@@ -4,12 +4,6 @@ Call chain:
|
|
|
4
4
|
formula.build_design_matrices() -> treatment_coding() / sum_coding() / ... (categorical columns)
|
|
5
5
|
marginal.build_reference_grid() -> build_reference_row() (EMM reference grids)
|
|
6
6
|
formula.build_random_effects_from_spec() -> build_z_simple() / build_z_nested() / build_z_crossed()
|
|
7
|
-
|
|
8
|
-
Submodules:
|
|
9
|
-
coding: Contrast matrix builders for categorical encoding (treatment, sum, helmert, poly)
|
|
10
|
-
names: Design matrix column name parsing and variable type detection
|
|
11
|
-
reference: Reference design matrix (X_ref) for marginal effects
|
|
12
|
-
z_matrix: Sparse Z matrix (random effects design matrix) construction
|
|
13
7
|
"""
|
|
14
8
|
|
|
15
9
|
from .coding import (
|
|
@@ -2,29 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Call chain:
|
|
4
4
|
model.fit() -> fit_model() -> resolve_solver() -> fit_ols_qr / fit_glm_irls / fit_lmer_pls / fit_glmer_pirls
|
|
5
|
-
|
|
6
|
-
Container flow:
|
|
7
|
-
Input: ModelSpec, DataBundle
|
|
8
|
-
Output: FitState (coef, vcov, fitted, residuals, loglik, theta for mixed)
|
|
9
|
-
|
|
10
|
-
Solver dispatch:
|
|
11
|
-
gaussian + no RE -> fit_ols_qr (QR decomposition)
|
|
12
|
-
gaussian + no RE -> fit_glm_irls (if method="ml")
|
|
13
|
-
non-gauss + no RE -> fit_glm_irls (IRLS)
|
|
14
|
-
gaussian + RE -> fit_lmer_pls (Penalized Least Squares)
|
|
15
|
-
non-gauss + RE -> fit_glmer_pirls (Penalized IRLS)
|
|
16
|
-
|
|
17
|
-
Submodules:
|
|
18
|
-
dispatch: Solver selection and fit_model entry point
|
|
19
|
-
ols: QR decomposition fitting (OLS/WLS)
|
|
20
|
-
glm: Iteratively Reweighted Least Squares (IRLS)
|
|
21
|
-
lmer: Penalized Least Squares (PLS) for LMM
|
|
22
|
-
glmer: Penalized IRLS (PIRLS) for GLMM
|
|
23
|
-
rank: Rank deficiency detection via pivoted QR
|
|
24
|
-
diagnostics: AIC/BIC, R-squared, metadata computation
|
|
25
|
-
convergence: Mixed model convergence checks (gradient, Hessian)
|
|
26
|
-
varying: BLUP extraction and variance component decomposition
|
|
27
|
-
predict: Prediction on training or new data
|
|
28
5
|
"""
|
|
29
6
|
|
|
30
7
|
from bossanova.internal.fit.convergence import check_convergence
|
|
@@ -105,7 +105,7 @@ def dispatch_solver(
|
|
|
105
105
|
tol: float | None = None,
|
|
106
106
|
verbose: bool = False,
|
|
107
107
|
nAGQ: int = 1,
|
|
108
|
-
use_hessian: bool =
|
|
108
|
+
use_hessian: bool = False,
|
|
109
109
|
) -> FitState:
|
|
110
110
|
"""Dispatch to the concrete solver implementation.
|
|
111
111
|
|
|
@@ -121,7 +121,7 @@ def dispatch_solver(
|
|
|
121
121
|
tol: Convergence tolerance (solver-specific defaults if None).
|
|
122
122
|
verbose: Print optimization progress (default: False).
|
|
123
123
|
nAGQ: Quadrature points for GLMER (default: 1).
|
|
124
|
-
use_hessian: Use Hessian-based vcov for GLMER (default:
|
|
124
|
+
use_hessian: Use Hessian-based vcov for GLMER (default: False).
|
|
125
125
|
|
|
126
126
|
Returns:
|
|
127
127
|
FitState from the selected solver.
|
|
@@ -172,7 +172,7 @@ def fit_model(
|
|
|
172
172
|
tol: float | None = None,
|
|
173
173
|
verbose: bool = False,
|
|
174
174
|
nAGQ: int = 1,
|
|
175
|
-
use_hessian: bool =
|
|
175
|
+
use_hessian: bool = False,
|
|
176
176
|
) -> FitState:
|
|
177
177
|
"""Dispatch to appropriate fitter based on model specification.
|
|
178
178
|
|
|
@@ -205,7 +205,7 @@ def fit_model(
|
|
|
205
205
|
tol: Convergence tolerance (solver-specific defaults if None).
|
|
206
206
|
verbose: Print optimization progress (default: False).
|
|
207
207
|
nAGQ: Quadrature points for GLMER (default: 1).
|
|
208
|
-
use_hessian: Use Hessian-based vcov for GLMER (default:
|
|
208
|
+
use_hessian: Use Hessian-based vcov for GLMER (default: False).
|
|
209
209
|
|
|
210
210
|
Returns:
|
|
211
211
|
FitState containing all fitting results.
|
|
@@ -29,7 +29,7 @@ def fit_glmer_pirls(
|
|
|
29
29
|
tol: float = 1e-7,
|
|
30
30
|
verbose: bool = False,
|
|
31
31
|
nAGQ: int = 1,
|
|
32
|
-
use_hessian: bool =
|
|
32
|
+
use_hessian: bool = False,
|
|
33
33
|
) -> FitState:
|
|
34
34
|
"""Fit generalized linear mixed model using Penalized IRLS.
|
|
35
35
|
|
|
@@ -70,7 +70,10 @@ def fit_glmer_pirls(
|
|
|
70
70
|
tol: PIRLS convergence tolerance (default: 1e-7).
|
|
71
71
|
verbose: Print optimization progress (default: False).
|
|
72
72
|
nAGQ: Quadrature points (0 or 1, default: 1).
|
|
73
|
-
use_hessian: Use Hessian-based vcov (default:
|
|
73
|
+
use_hessian: Use Hessian-based vcov (default: False). The default
|
|
74
|
+
Schur complement approach matches lme4's ``vcov()`` with
|
|
75
|
+
``use.hessian=FALSE`` and avoids expensive numerical
|
|
76
|
+
differentiation. Set to True for observed-information vcov.
|
|
74
77
|
|
|
75
78
|
Returns:
|
|
76
79
|
FitState containing:
|
|
@@ -91,7 +94,6 @@ def fit_glmer_pirls(
|
|
|
91
94
|
- bossanova.internal.maths.solvers.glmer: Underlying PIRLS implementation
|
|
92
95
|
"""
|
|
93
96
|
from bossanova.internal.maths.solvers.glmer import (
|
|
94
|
-
compute_hessian_vcov,
|
|
95
97
|
compute_irls_quantities,
|
|
96
98
|
fit_glmm_pirls,
|
|
97
99
|
)
|
|
@@ -177,9 +179,17 @@ def fit_glmer_pirls(
|
|
|
177
179
|
converged = fit_result["converged"]
|
|
178
180
|
n_iter = fit_result["n_func_evals"]
|
|
179
181
|
|
|
182
|
+
# Compute IRLS weights once (needed by both vcov paths and for XtWX_inv)
|
|
183
|
+
working_weights, _ = compute_irls_quantities(y, eta, family)
|
|
184
|
+
if weights is not None:
|
|
185
|
+
total_weights = weights * working_weights
|
|
186
|
+
else:
|
|
187
|
+
total_weights = working_weights
|
|
188
|
+
|
|
180
189
|
# Compute variance-covariance matrix of beta
|
|
181
190
|
if use_hessian:
|
|
182
|
-
|
|
191
|
+
from bossanova.internal.maths.solvers.glmer import compute_hessian_vcov
|
|
192
|
+
|
|
183
193
|
vcov, _ = compute_hessian_vcov(
|
|
184
194
|
theta=theta,
|
|
185
195
|
beta=beta,
|
|
@@ -196,15 +206,7 @@ def fit_glmer_pirls(
|
|
|
196
206
|
eta_init=eta, # Use optimal eta as starting point
|
|
197
207
|
)
|
|
198
208
|
else:
|
|
199
|
-
# Schur complement-based vcov (
|
|
200
|
-
working_weights, _ = compute_irls_quantities(y, eta, family)
|
|
201
|
-
|
|
202
|
-
if weights is not None:
|
|
203
|
-
total_weights = weights * working_weights
|
|
204
|
-
else:
|
|
205
|
-
total_weights = working_weights
|
|
206
|
-
|
|
207
|
-
# Build Lambda for Schur complement
|
|
209
|
+
# Schur complement-based vcov (analytical, matches lme4 vcov(use.hessian=FALSE))
|
|
208
210
|
Lambda = build_lambda_sparse(theta, n_groups_list, re_structure, metadata)
|
|
209
211
|
vcov = compute_vcov_schur_sparse(X, Z, Lambda, weights=total_weights)
|
|
210
212
|
|
|
@@ -218,13 +220,8 @@ def fit_glmer_pirls(
|
|
|
218
220
|
# Degrees of freedom
|
|
219
221
|
df_resid = float(n - p)
|
|
220
222
|
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
-
if weights is not None:
|
|
224
|
-
final_irls_weights = weights * final_working_weights
|
|
225
|
-
else:
|
|
226
|
-
final_irls_weights = final_working_weights
|
|
227
|
-
XtWX = X.T @ (X * final_irls_weights[:, np.newaxis])
|
|
223
|
+
# XtWX_inv for sandwich/cluster-robust SEs (reuse total_weights)
|
|
224
|
+
XtWX = X.T @ (X * total_weights[:, np.newaxis])
|
|
228
225
|
XtWX_inv = np.linalg.inv(XtWX)
|
|
229
226
|
|
|
230
227
|
return build_fit_state(
|
|
@@ -240,6 +237,6 @@ def fit_glmer_pirls(
|
|
|
240
237
|
u=u,
|
|
241
238
|
converged=converged,
|
|
242
239
|
n_iter=n_iter,
|
|
243
|
-
irls_weights=
|
|
240
|
+
irls_weights=total_weights,
|
|
244
241
|
XtWX_inv=XtWX_inv,
|
|
245
242
|
)
|
|
@@ -3,25 +3,6 @@
|
|
|
3
3
|
Call chain:
|
|
4
4
|
model(formula, data) -> parse_formula() -> build_bundle_from_data() -> build_design_matrices()
|
|
5
5
|
model.predict(newdata=) -> evaluate_newdata() (applies learned encoding to new observations)
|
|
6
|
-
|
|
7
|
-
Container flow:
|
|
8
|
-
Input: formula string + Polars DataFrame
|
|
9
|
-
Output: FormulaSpec (via parse_formula) + DataBundle (X, y, Z matrices via build_design_matrices)
|
|
10
|
-
|
|
11
|
-
Submodules:
|
|
12
|
-
parse: R-style formula string parsing into FormulaSpec
|
|
13
|
-
parser/: Recursive descent parser (scanner, tokens, AST nodes)
|
|
14
|
-
design: Design matrix construction from FormulaSpec
|
|
15
|
-
evaluate: Term evaluation (AST nodes to design matrix columns)
|
|
16
|
-
evaluate_transforms: Stateful, math, and polynomial transforms
|
|
17
|
-
evaluate_contrast: Contrast function evaluation for categorical encoding
|
|
18
|
-
evaluate_newdata: Apply learned encoding to new observations
|
|
19
|
-
encoding: Categorical variable encoding using Polars Enum
|
|
20
|
-
random_effects: Z matrix construction from FormulaSpec
|
|
21
|
-
helpers: Shared AST utilities
|
|
22
|
-
bundle: DataBundle construction from formula + DataFrame
|
|
23
|
-
contrast_registry: Contrast function vocabulary and validation
|
|
24
|
-
contrast_specs: User-facing contrast specification resolution
|
|
25
6
|
"""
|
|
26
7
|
|
|
27
8
|
from bossanova.internal.formula.design import (
|
|
@@ -1,31 +1,8 @@
|
|
|
1
1
|
"""Inference operations: asymptotic, bootstrap, permutation, cross-validation, profile, and simulation.
|
|
2
2
|
|
|
3
|
-
Provides asymptotic (Wald-based), bootstrap, permutation, cross-validation,
|
|
4
|
-
profile likelihood, and simulation inference for parameters, marginal effects,
|
|
5
|
-
predictions, and variance components.
|
|
6
|
-
|
|
7
3
|
Call chain:
|
|
8
4
|
model.infer() -> dispatch_infer() -> dispatch_{params,mee,prediction}_inference()
|
|
9
5
|
Each dispatcher routes to the method-specific backend (asymptotic, bootstrap, etc.)
|
|
10
|
-
|
|
11
|
-
Container flow:
|
|
12
|
-
Input: ModelSpec, DataBundle, FitState (+ MeeState for effects, PredictionState for predictions)
|
|
13
|
-
Output: InferenceState (SE, CI, p-values) augmented onto the target state
|
|
14
|
-
|
|
15
|
-
Submodules:
|
|
16
|
-
dispatch: Top-level infer routing
|
|
17
|
-
params: Parameter inference dispatch
|
|
18
|
-
mee: Marginal effects inference dispatch
|
|
19
|
-
prediction: Prediction inference dispatch
|
|
20
|
-
asymptotic: Wald-based SEs, CIs, p-values
|
|
21
|
-
bootstrap: Parametric and nonparametric bootstrap
|
|
22
|
-
permutation: Permutation tests for params and effects
|
|
23
|
-
cv: K-fold and group-K-fold cross-validation
|
|
24
|
-
profile: Profile likelihood for variance components
|
|
25
|
-
simulation: Summary statistics across simulation replicates
|
|
26
|
-
satterthwaite_emm: Satterthwaite df for EMM contrasts (mixed models)
|
|
27
|
-
resample/: Resampling engine (bootstrap indices, CI methods, model-type hooks)
|
|
28
|
-
formula_utils: Formula manipulation for term ablation (CV)
|
|
29
6
|
"""
|
|
30
7
|
|
|
31
8
|
from bossanova.internal.infer.asymptotic import (
|
|
@@ -189,6 +189,15 @@ def dispatch_infer(
|
|
|
189
189
|
threshold=threshold,
|
|
190
190
|
)
|
|
191
191
|
|
|
192
|
+
# --- CV with stale predict state: reroute to fit branch ---
|
|
193
|
+
# When last_op is "predict" but predictions were made on newdata (different
|
|
194
|
+
# n than training data), CV can't attach training-data-sized arrays to the
|
|
195
|
+
# prediction state. Fall back to the fit branch which produces model-level
|
|
196
|
+
# CV metrics (PRE, RMSE, etc.) — almost always what the user intended.
|
|
197
|
+
if how == "cv" and last_op == "predict" and pred is not None:
|
|
198
|
+
if len(pred.fitted) != bundle.n:
|
|
199
|
+
last_op = "fit"
|
|
200
|
+
|
|
192
201
|
# --- Dispatch based on last_op ---
|
|
193
202
|
match last_op:
|
|
194
203
|
case "fit":
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
"""Marginal effects and estimated marginal means computation.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
2. EMM/Slopes (compute_emm, compute_slopes): Predictions at grid points
|
|
6
|
-
3. Contrasts (compute_contrasts): Apply contrast matrices to EMM results
|
|
7
|
-
|
|
8
|
-
Provides:
|
|
9
|
-
- parse_explore_formula: Parse explore formula syntax
|
|
10
|
-
- ExploreFormula, ExploreFormulaError, Condition: Parsed explore formula types
|
|
11
|
-
- build_reference_grid: Construct evaluation grid from DataBundle
|
|
12
|
-
- compute_emm: Compute estimated marginal means at grid points
|
|
13
|
-
- compute_slopes: Compute marginal effects for continuous predictors
|
|
14
|
-
- compute_contrasts: Apply contrast matrices to EMM results
|
|
15
|
-
- matrices: EMM contrast matrix builders (build_*_matrix)
|
|
3
|
+
Call chain:
|
|
4
|
+
model.explore() -> build_reference_grid() -> compute_emm() / compute_slopes() -> compute_contrasts()
|
|
16
5
|
"""
|
|
17
6
|
|
|
18
7
|
from bossanova.internal.marginal.explore import (
|
|
@@ -312,6 +312,15 @@ def compute_slopes_finite_diff(
|
|
|
312
312
|
|
|
313
313
|
validate_focal_var(bundle, focal_var)
|
|
314
314
|
|
|
315
|
+
# --- drop rows with missing values in model variables -----------------
|
|
316
|
+
# The caller may pass raw data that includes rows dropped during fitting.
|
|
317
|
+
# Null/NaN values propagate through matrix multiplication and corrupt the
|
|
318
|
+
# AME estimate, so filter to complete cases on the model's columns.
|
|
319
|
+
model_cols = [c for c in bundle.X_names if c in data.columns]
|
|
320
|
+
if bundle.y_name in data.columns:
|
|
321
|
+
model_cols.append(bundle.y_name)
|
|
322
|
+
data = data.drop_nulls(subset=model_cols)
|
|
323
|
+
|
|
315
324
|
# --- step size --------------------------------------------------------
|
|
316
325
|
focal_col = data[focal_var].cast(pl.Float64).to_numpy()
|
|
317
326
|
var_range = float(focal_col.max() - focal_col.min())
|
|
@@ -443,6 +452,12 @@ def compute_slopes_crossed(
|
|
|
443
452
|
"(needed by evaluate_newdata)."
|
|
444
453
|
)
|
|
445
454
|
|
|
455
|
+
# --- drop rows with missing values in model variables -----------------
|
|
456
|
+
model_cols = [c for c in bundle.X_names if c in data.columns]
|
|
457
|
+
if bundle.y_name in data.columns:
|
|
458
|
+
model_cols.append(bundle.y_name)
|
|
459
|
+
data = data.drop_nulls(subset=model_cols)
|
|
460
|
+
|
|
446
461
|
# --- step size --------------------------------------------------------
|
|
447
462
|
focal_col = data[focal_var].cast(pl.Float64).to_numpy()
|
|
448
463
|
var_range = float(focal_col.max() - focal_col.min())
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""LaTeX equation and markdown rendering for model output.
|
|
2
|
+
|
|
3
|
+
Call chain:
|
|
4
|
+
model.equation() -> build_equation(spec) -> LaTeX string
|
|
5
|
+
model_result.to_markdown() -> dataframe_to_markdown(df) -> markdown string
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from bossanova.internal.rendering.latex import build_equation
|
|
9
|
+
from bossanova.internal.rendering.markdown import (
|
|
10
|
+
dataframe_to_markdown,
|
|
11
|
+
equation_to_markdown,
|
|
12
|
+
to_markdown,
|
|
13
|
+
write_text,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"build_equation",
|
|
18
|
+
"dataframe_to_markdown",
|
|
19
|
+
"equation_to_markdown",
|
|
20
|
+
"to_markdown",
|
|
21
|
+
"write_text",
|
|
22
|
+
]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Markdown table and equation rendering for report export.
|
|
2
|
+
|
|
3
|
+
Pure functions that convert Polars DataFrames and LaTeX equations into
|
|
4
|
+
pipe-delimited GitHub Flavored Markdown / Quarto-compatible text.
|
|
5
|
+
Used by ``ModelResult.to_markdown()``, ``MathDisplay.to_markdown()``,
|
|
6
|
+
and the top-level ``bossanova.to_markdown()`` utility.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import polars as pl
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"dataframe_to_markdown",
|
|
17
|
+
"equation_to_markdown",
|
|
18
|
+
"to_markdown",
|
|
19
|
+
"write_text",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def dataframe_to_markdown(
|
|
24
|
+
df: pl.DataFrame,
|
|
25
|
+
caption: str | None = None,
|
|
26
|
+
) -> str:
|
|
27
|
+
"""Convert a Polars DataFrame to a pipe-delimited markdown table.
|
|
28
|
+
|
|
29
|
+
Produces GitHub Flavored Markdown (GFM) table syntax that renders
|
|
30
|
+
correctly in Quarto, GitHub, and most markdown environments. Columns
|
|
31
|
+
are padded to align visually. Null values render as empty cells.
|
|
32
|
+
|
|
33
|
+
No additional numeric formatting is applied — the DataFrame is assumed
|
|
34
|
+
to be pre-rounded (as all bossanova result DataFrames are).
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
df: Polars DataFrame to convert.
|
|
38
|
+
caption: Optional table caption. Rendered as ``Table: {caption}``
|
|
39
|
+
above the table (Quarto cross-reference syntax).
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Pipe-delimited markdown table as a string.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
>>> import polars as pl
|
|
46
|
+
>>> df = pl.DataFrame({"x": [1, 2], "y": [3.14, 2.72]})
|
|
47
|
+
>>> print(dataframe_to_markdown(df))
|
|
48
|
+
| x | y |
|
|
49
|
+
|---|------|
|
|
50
|
+
| 1 | 3.14 |
|
|
51
|
+
| 2 | 2.72 |
|
|
52
|
+
"""
|
|
53
|
+
cols = df.columns
|
|
54
|
+
|
|
55
|
+
# Convert all values to strings, rendering nulls as empty
|
|
56
|
+
str_rows: list[list[str]] = []
|
|
57
|
+
for row in df.iter_rows():
|
|
58
|
+
str_rows.append([("" if v is None else str(v)) for v in row])
|
|
59
|
+
|
|
60
|
+
# Compute column widths (minimum 3 for the separator dashes)
|
|
61
|
+
widths = [max(3, len(c)) for c in cols]
|
|
62
|
+
for row in str_rows:
|
|
63
|
+
for i, cell in enumerate(row):
|
|
64
|
+
widths[i] = max(widths[i], len(cell))
|
|
65
|
+
|
|
66
|
+
# Build table lines
|
|
67
|
+
header = "| " + " | ".join(c.ljust(widths[i]) for i, c in enumerate(cols)) + " |"
|
|
68
|
+
separator = "|" + "|".join("-" * (w + 2) for w in widths) + "|"
|
|
69
|
+
data_lines = [
|
|
70
|
+
"| " + " | ".join(cell.ljust(widths[i]) for i, cell in enumerate(row)) + " |"
|
|
71
|
+
for row in str_rows
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
parts: list[str] = []
|
|
75
|
+
if caption is not None:
|
|
76
|
+
parts.append(f"Table: {caption}")
|
|
77
|
+
parts.append("")
|
|
78
|
+
parts.append(header)
|
|
79
|
+
parts.append(separator)
|
|
80
|
+
parts.extend(data_lines)
|
|
81
|
+
return "\n".join(parts)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def equation_to_markdown(
|
|
85
|
+
equation: str,
|
|
86
|
+
explanations: tuple[str, ...] = (),
|
|
87
|
+
*,
|
|
88
|
+
include_explanations: bool = True,
|
|
89
|
+
) -> str:
|
|
90
|
+
r"""Wrap a LaTeX equation in display math delimiters for Quarto.
|
|
91
|
+
|
|
92
|
+
Produces ``$$...$$`` display math that Quarto renders natively in
|
|
93
|
+
Typst, HTML, and PDF output. Optionally appends term explanations
|
|
94
|
+
as plain text below the equation block.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
equation: LaTeX equation string (without ``$$`` delimiters).
|
|
98
|
+
explanations: Term explanation strings from ``MathDisplay``.
|
|
99
|
+
include_explanations: If True (default), append explanations
|
|
100
|
+
as plain text lines below the equation.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Markdown string with display math block and optional explanations.
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
>>> print(equation_to_markdown(r"y = \beta_0 + \beta_1 x"))
|
|
107
|
+
$$
|
|
108
|
+
y = \beta_0 + \beta_1 x
|
|
109
|
+
$$
|
|
110
|
+
"""
|
|
111
|
+
parts = [f"$$\n{equation}\n$$"]
|
|
112
|
+
if include_explanations and explanations:
|
|
113
|
+
parts.append("")
|
|
114
|
+
for exp in explanations:
|
|
115
|
+
parts.append(f"- {exp}")
|
|
116
|
+
return "\n".join(parts)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def write_text(text: str, path: str | Path) -> None:
|
|
120
|
+
"""Write text content to a file, creating parent directories.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
path: Destination file path. Parent directories are created
|
|
124
|
+
automatically if they don't exist.
|
|
125
|
+
text: Text content to write.
|
|
126
|
+
"""
|
|
127
|
+
dest = Path(path)
|
|
128
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
129
|
+
dest.write_text(text, encoding="utf-8")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def to_markdown(
|
|
133
|
+
df: pl.DataFrame,
|
|
134
|
+
path: str | Path | None = None,
|
|
135
|
+
caption: str | None = None,
|
|
136
|
+
) -> str:
|
|
137
|
+
"""Convert a Polars DataFrame to a markdown table, optionally saving to file.
|
|
138
|
+
|
|
139
|
+
Standalone utility for DataFrames not wrapped in ``ModelResult`` —
|
|
140
|
+
such as results from ``compare()``, ``model.jointtest()``,
|
|
141
|
+
``model.vif()``, ``model.to_odds_ratio()``, etc.
|
|
142
|
+
|
|
143
|
+
For ``ModelResult`` objects (returned by ``.fit()``, ``.infer()``,
|
|
144
|
+
etc.), use ``result.to_markdown()`` instead.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
df: Polars DataFrame to convert.
|
|
148
|
+
path: Optional file path. If given, writes the markdown and
|
|
149
|
+
creates parent directories automatically.
|
|
150
|
+
caption: Optional table caption (``Table: ...`` Quarto syntax).
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Pipe-delimited markdown table as a string.
|
|
154
|
+
|
|
155
|
+
Examples:
|
|
156
|
+
>>> from bossanova import compare, to_markdown
|
|
157
|
+
>>> to_markdown(compare(m1, m2), "comparison.md", caption="Model Comparison")
|
|
158
|
+
>>> md = to_markdown(m.jointtest()) # string only
|
|
159
|
+
"""
|
|
160
|
+
text = dataframe_to_markdown(df, caption=caption)
|
|
161
|
+
if path is not None:
|
|
162
|
+
write_text(text, path)
|
|
163
|
+
return text
|
|
@@ -4,18 +4,6 @@ Call chain:
|
|
|
4
4
|
model.simulate(n=...) -> generate_{lm,glm,lmer,glmer}_data() (pre-fit DGP)
|
|
5
5
|
model.simulate(nsim=...) -> simulate_responses_from_fit() (post-fit parametric bootstrap)
|
|
6
6
|
run_power_study(formula, ...) -> run_power_analysis() -> expand_sweep_grid()
|
|
7
|
-
|
|
8
|
-
Container flow:
|
|
9
|
-
Pre-fit: SimulationSpec + VaryingSpec -> DataBundle (synthetic data)
|
|
10
|
-
Post-fit: FitState -> simulated response arrays
|
|
11
|
-
Power: sweep parameters -> Polars DataFrame (power results)
|
|
12
|
-
|
|
13
|
-
Submodules:
|
|
14
|
-
dgp/: Data generating process functions (lm, glm, lmer, glmer)
|
|
15
|
-
model_sim: Response simulation from fitted model parameters
|
|
16
|
-
harness: Monte Carlo iteration runner and MonteCarloResult container
|
|
17
|
-
metrics: Recovery metrics (bias, RMSE, coverage, rejection rate)
|
|
18
|
-
power: Power analysis and parameter sweep utilities
|
|
19
7
|
"""
|
|
20
8
|
|
|
21
9
|
from bossanova.internal.simulation.dgp import (
|