bossanova 0.1.0.dev15__tar.gz → 0.1.0.dev17__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.dev15 → bossanova-0.1.0.dev17}/PKG-INFO +1 -1
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/state.py +9 -3
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/state.py +14 -9
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/reference.py +93 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/bracket_contrasts.py +4 -4
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/compute.py +81 -43
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/emm.py +197 -38
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/inference.py +2 -2
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/slopes.py +87 -48
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/core_protocols.py +27 -7
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/fit_builders.py +3 -1
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/helpers.py +6 -2
- bossanova-0.1.0.dev17/bossanova/model/__init__.py +6 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/model/core.py +26 -18
- bossanova-0.1.0.dev17/bossanova/model/result.py +109 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/pyproject.toml +4 -2
- bossanova-0.1.0.dev15/bossanova/model/__init__.py +0 -5
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/.gitignore +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/LICENSE +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/README.md +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/README.md +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/advertising.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/cake.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/chickweight.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/credit.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/gammas.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/mtcars.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/penguins.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/poker.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/sleep.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/titanic.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/titanic_test.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/data/titanic_train.csv +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/distributions/continuous.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/distributions/discrete.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/distributions/varying.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/expressions.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/data.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/dataframes.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/resamples.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/results.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/specs.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/schemas.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/data.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/display.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/explore.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/formula.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/specs.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/validators.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/backend/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/backend/dispatch.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/backend/jax.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/backend/numpy.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/backend/protocol.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/batching.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/config.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/convergence.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/coding.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/names.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/z_matrix.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/differentiation.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/algebra.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/base.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/core.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/derived.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/factories.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/plotting.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/distributions/probability.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/binomial.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/create.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/gamma.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/gaussian.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/links.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/poisson.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/response.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/schema.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/family/tdist.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/contrasts.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/diagnostics.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/estimation.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/hypothesis.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/information_criteria.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/multiplicity.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/profile.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/sandwich.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/satterthwaite.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/wald_variance.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/inference/welch.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/linalg/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/linalg/qr.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/linalg/schur.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/linalg/sparse.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/linalg/svd.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/predict.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/rng.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/rounding.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/glm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/glmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/heuristics.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/initialization.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/lambda_builder.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/lambda_sparse.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/lambda_template.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/lmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/optimize.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/pirls_sparse.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/solvers/quadrature.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/tolerances.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/transforms.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/variance.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/weights.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/bundle.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/common/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/common/contrast_registry.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/common/data_utils.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/common/factors.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/common/formula_utils.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/compare.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/cv.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/deviance.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/f_test.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/helpers.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/lrt.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/lrt_compare.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/compare/refit.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/contrasts.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/convergence.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/diagnostics.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/dispatch.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/glm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/glmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/lmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/ols.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/fit/rank.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/design.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/encoding.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/evaluate.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/evaluate_newdata.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/evaluate_transforms.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/helpers.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parse.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parser/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parser/expr.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parser/parser.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parser/scanner.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/parser/token.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/formula/random_effects.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/asymptotic.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/bootstrap.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/cv.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/mee.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/params.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/permutation.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/prediction.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/profile.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/resample_bundle.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/satterthwaite_emm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/infer/simulation.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/conditions.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/contrasts.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/explore.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/explore_parser.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/explore_scanner.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/grid.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/joint_tests.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/validation.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/predict.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/profile.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/rendering/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/rendering/latex.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/common.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/core.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/glm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/glmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/lm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/lm_bca.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/lm_operators.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/lmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/mixed.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/results.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/resample/utils.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/generate.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/glm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/glmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/lm.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/dgp/lmer.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/harness.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/metrics.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/model_sim.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/simulation/power.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/transforms.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/varying.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/README.md +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/__init__.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/cognition.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/compare.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/core.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/core_data.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/core_sizing.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/core_viz.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/dag.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/design.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/fit.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/fit_layers.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/lattice.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/layout.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/mem.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/params.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/predict.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/profile.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/ranef.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/relationships.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/resamples.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/resid.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/viz/vif.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/model/guards.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/model/summary.py +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/py.typed +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/tests/bossanova_benchmarks/bootstrap/data/README.md +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/tests/bossanova_benchmarks/insteval/data/README.md +0 -0
- {bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/tests/bossanova_tests/hypothesis/README.md +0 -0
{bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/builders/state.py
RENAMED
|
@@ -196,7 +196,8 @@ def build_mee_state(
|
|
|
196
196
|
focal_var: str,
|
|
197
197
|
mee_type: str,
|
|
198
198
|
*,
|
|
199
|
-
|
|
199
|
+
how: str = "mem",
|
|
200
|
+
effect_scale: str = "link",
|
|
200
201
|
L_matrix: np.ndarray | None = None,
|
|
201
202
|
contrast_method: str | None = None,
|
|
202
203
|
n_contrast_levels: int | None = None,
|
|
@@ -218,7 +219,11 @@ def build_mee_state(
|
|
|
218
219
|
explore_formula: The explore formula string.
|
|
219
220
|
focal_var: The primary variable being explored.
|
|
220
221
|
mee_type: Type of effect ("means", "slopes", "contrasts").
|
|
221
|
-
|
|
222
|
+
how: Averaging method: ``"mem"`` (Marginal Estimated Mean,
|
|
223
|
+
balanced reference grid) or ``"ame"`` (Average Marginal
|
|
224
|
+
Effect, g-computation over observed data).
|
|
225
|
+
effect_scale: Scale of estimates: ``"link"`` (linear predictor)
|
|
226
|
+
or ``"response"`` (inverse-link / data scale).
|
|
222
227
|
L_matrix: Design matrix for delta method inference (optional).
|
|
223
228
|
Shape (n_estimates, n_coef). For EMMs this is X_ref.
|
|
224
229
|
contrast_method: Original contrast type for multiplicity adjustment
|
|
@@ -257,7 +262,8 @@ def build_mee_state(
|
|
|
257
262
|
explore_formula=explore_formula,
|
|
258
263
|
focal_var=focal_var,
|
|
259
264
|
type=mee_type,
|
|
260
|
-
|
|
265
|
+
how=how,
|
|
266
|
+
effect_scale=effect_scale,
|
|
261
267
|
L_matrix=L_matrix,
|
|
262
268
|
contrast_method=contrast_method,
|
|
263
269
|
n_contrast_levels=n_contrast_levels,
|
{bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/containers/structs/state.py
RENAMED
|
@@ -219,18 +219,21 @@ class MeeState:
|
|
|
219
219
|
explore_formula: The explore formula string that generated this result.
|
|
220
220
|
focal_var: The primary variable being explored.
|
|
221
221
|
type: Type of marginal effect ("means", "slopes", "contrasts").
|
|
222
|
-
|
|
223
|
-
emmeans-style) or ``"
|
|
222
|
+
how: Averaging method: ``"mem"`` (Marginal Estimated Mean, balanced
|
|
223
|
+
reference grid, emmeans-style) or ``"ame"`` (Average Marginal
|
|
224
|
+
Effect, g-computation over observed data).
|
|
225
|
+
effect_scale: Scale of estimates: ``"link"`` (linear predictor) or
|
|
226
|
+
``"response"`` (inverse-link / data scale).
|
|
224
227
|
L_matrix: Design matrix for delta method inference. Shape (n_estimates, n_coef).
|
|
225
228
|
For EMMs, this is X_ref; for slopes, a coefficient selector row.
|
|
226
229
|
contrast_method: Original contrast type for multiplicity adjustment
|
|
227
230
|
("pairwise", "sequential", "poly", "treatment", "sum",
|
|
228
231
|
"helmert", or None).
|
|
229
232
|
n_contrast_levels: Number of EMM levels before contrasting (family size for Tukey).
|
|
230
|
-
link: Link function name for response-scale back-transformation (set when
|
|
231
|
-
and
|
|
232
|
-
L_matrix_link: Link-scale L_matrix for CI back-transformation (set when
|
|
233
|
-
and
|
|
233
|
+
link: Link function name for response-scale back-transformation (set when
|
|
234
|
+
effect_scale="response" and how="mem").
|
|
235
|
+
L_matrix_link: Link-scale L_matrix for CI back-transformation (set when
|
|
236
|
+
effect_scale="response" and how="mem").
|
|
234
237
|
inference_method: Inference method used (``"asymp"``, ``"boot"``,
|
|
235
238
|
``"perm"``, or ``None``). Controls which columns appear in
|
|
236
239
|
the ``.effects`` DataFrame.
|
|
@@ -257,8 +260,10 @@ class MeeState:
|
|
|
257
260
|
explore_formula: str = field(validator=validators.instance_of(str))
|
|
258
261
|
focal_var: str = field(validator=validators.instance_of(str))
|
|
259
262
|
type: str = field(validator=validators.in_(("means", "slopes", "contrasts")))
|
|
260
|
-
|
|
261
|
-
|
|
263
|
+
how: str = field(default="mem", validator=validators.in_(("mem", "ame")))
|
|
264
|
+
effect_scale: str = field(
|
|
265
|
+
default="link", validator=validators.in_(("link", "response"))
|
|
266
|
+
)
|
|
262
267
|
|
|
263
268
|
# Design matrix for delta method inference (optional)
|
|
264
269
|
# Shape: (n_estimates, n_coef). For EMMs, this is X_ref; for slopes, a selector row.
|
|
@@ -285,7 +290,7 @@ class MeeState:
|
|
|
285
290
|
)
|
|
286
291
|
n_contrast_levels: int | None = field(default=None)
|
|
287
292
|
|
|
288
|
-
# Response-scale back-transformation (set when
|
|
293
|
+
# Response-scale back-transformation (set when effect_scale="response" for GLM/GLMER)
|
|
289
294
|
link: str | None = field(default=None)
|
|
290
295
|
L_matrix_link: np.ndarray | None = field(
|
|
291
296
|
default=None, repr=False, validator=is_optional_ndarray
|
{bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/maths/design/reference.py
RENAMED
|
@@ -9,6 +9,7 @@ from bossanova.internal.maths.design.names import (
|
|
|
9
9
|
|
|
10
10
|
__all__ = [
|
|
11
11
|
"build_continuous_reference_matrix",
|
|
12
|
+
"build_counterfactual_design_matrices",
|
|
12
13
|
"build_reference_design_matrix",
|
|
13
14
|
"build_reference_row",
|
|
14
15
|
]
|
|
@@ -248,6 +249,98 @@ def build_continuous_reference_matrix(
|
|
|
248
249
|
return X_ref
|
|
249
250
|
|
|
250
251
|
|
|
252
|
+
def build_counterfactual_design_matrices(
|
|
253
|
+
X: np.ndarray,
|
|
254
|
+
X_names: tuple[str, ...] | list[str],
|
|
255
|
+
focal_var: str,
|
|
256
|
+
levels: list[str],
|
|
257
|
+
) -> list[np.ndarray]:
|
|
258
|
+
"""Build counterfactual design matrices for g-computation.
|
|
259
|
+
|
|
260
|
+
For each focal level, creates a modified copy of the full design matrix
|
|
261
|
+
``X`` where the focal variable's indicator columns are set to match that
|
|
262
|
+
level and interaction columns involving the focal variable are recomputed
|
|
263
|
+
from component values. Non-focal columns are left unchanged, preserving
|
|
264
|
+
the observed covariate distribution.
|
|
265
|
+
|
|
266
|
+
This is the core building block for ``weights="observed"``
|
|
267
|
+
(g-computation / counterfactual prediction). Each returned matrix answers:
|
|
268
|
+
"What would the design matrix look like if every observation were assigned
|
|
269
|
+
to this focal level?"
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
X: Original design matrix, shape ``(N, p)``.
|
|
273
|
+
X_names: Column names from the design matrix, in order.
|
|
274
|
+
focal_var: Name of the categorical focal variable.
|
|
275
|
+
levels: List of levels to compute counterfactuals for.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
List of counterfactual design matrices (one per level), each shape
|
|
279
|
+
``(N, p)``. Order matches ``levels``.
|
|
280
|
+
|
|
281
|
+
Examples:
|
|
282
|
+
For a model ``y ~ treatment + x + treatment:x`` with
|
|
283
|
+
``X_names = ("Intercept", "x", "treatment[B]", "x:treatment[B]")``::
|
|
284
|
+
|
|
285
|
+
mats = build_counterfactual_design_matrices(X, X_names, "treatment", ["ref", "B"])
|
|
286
|
+
# mats[0]: treatment set to ref for all rows (treatment[B]=0, x:treatment[B]=0)
|
|
287
|
+
# mats[1]: treatment set to B for all rows (treatment[B]=1, x:treatment[B]=x_i)
|
|
288
|
+
"""
|
|
289
|
+
X_names_list = list(X_names)
|
|
290
|
+
N, p = X.shape
|
|
291
|
+
|
|
292
|
+
# Pre-parse column metadata once
|
|
293
|
+
col_infos = [parse_design_column_name(name) for name in X_names_list]
|
|
294
|
+
|
|
295
|
+
# Identify focal dummy columns and their levels
|
|
296
|
+
focal_col_indices: list[int] = []
|
|
297
|
+
focal_col_levels: list[str | None] = []
|
|
298
|
+
for j, info in enumerate(col_infos):
|
|
299
|
+
if info.column_type == "categorical" and info.base_term == focal_var:
|
|
300
|
+
focal_col_indices.append(j)
|
|
301
|
+
focal_col_levels.append(info.level)
|
|
302
|
+
|
|
303
|
+
# Identify interaction columns involving the focal variable
|
|
304
|
+
interaction_cols: list[int] = []
|
|
305
|
+
for j, info in enumerate(col_infos):
|
|
306
|
+
if info.is_interaction:
|
|
307
|
+
parts = X_names_list[j].split(":")
|
|
308
|
+
if any(
|
|
309
|
+
parse_design_column_name(part).base_term == focal_var for part in parts
|
|
310
|
+
):
|
|
311
|
+
interaction_cols.append(j)
|
|
312
|
+
|
|
313
|
+
result: list[np.ndarray] = []
|
|
314
|
+
for level in levels:
|
|
315
|
+
X_cf = X.copy()
|
|
316
|
+
|
|
317
|
+
# Set focal dummy columns
|
|
318
|
+
for j, lvl in zip(focal_col_indices, focal_col_levels):
|
|
319
|
+
X_cf[:, j] = 1.0 if lvl == level else 0.0
|
|
320
|
+
|
|
321
|
+
# Recompute interaction columns involving the focal variable
|
|
322
|
+
for j in interaction_cols:
|
|
323
|
+
parts = X_names_list[j].split(":")
|
|
324
|
+
col_product = np.ones(N, dtype=np.float64)
|
|
325
|
+
for part in parts:
|
|
326
|
+
pinfo = parse_design_column_name(part)
|
|
327
|
+
if pinfo.base_term == focal_var:
|
|
328
|
+
# Focal component: use counterfactual indicator
|
|
329
|
+
if pinfo.column_type == "categorical":
|
|
330
|
+
col_product *= 1.0 if pinfo.level == level else 0.0
|
|
331
|
+
elif part in X_names_list:
|
|
332
|
+
# Continuous focal in interaction (rare but possible)
|
|
333
|
+
col_product *= X[:, X_names_list.index(part)]
|
|
334
|
+
elif part in X_names_list:
|
|
335
|
+
# Non-focal component: use original observed values
|
|
336
|
+
col_product *= X[:, X_names_list.index(part)]
|
|
337
|
+
X_cf[:, j] = col_product
|
|
338
|
+
|
|
339
|
+
result.append(X_cf)
|
|
340
|
+
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
|
|
251
344
|
# ---------------------------------------------------------------------------
|
|
252
345
|
# Internal helpers
|
|
253
346
|
# ---------------------------------------------------------------------------
|
|
@@ -304,7 +304,7 @@ def compute_compound_bracket_contrasts(
|
|
|
304
304
|
*,
|
|
305
305
|
data: pl.DataFrame,
|
|
306
306
|
spec: object | None = None,
|
|
307
|
-
|
|
307
|
+
effect_scale: str = "link",
|
|
308
308
|
resolved: object | None = None,
|
|
309
309
|
) -> MeeState:
|
|
310
310
|
"""Compute bracket contrasts for a compound focal variable.
|
|
@@ -324,7 +324,7 @@ def compute_compound_bracket_contrasts(
|
|
|
324
324
|
contrast_expr: ContrastExpr from the parser.
|
|
325
325
|
data: Model data DataFrame.
|
|
326
326
|
spec: ModelSpec with link/family info.
|
|
327
|
-
|
|
327
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
328
328
|
resolved: ResolvedConditions for additional conditioning.
|
|
329
329
|
|
|
330
330
|
Returns:
|
|
@@ -396,7 +396,7 @@ def compute_compound_bracket_contrasts(
|
|
|
396
396
|
# Handle response-scale transformation
|
|
397
397
|
L_matrix: np.ndarray = X_ref
|
|
398
398
|
link_name: str | None = None
|
|
399
|
-
if
|
|
399
|
+
if effect_scale == "response" and spec is not None:
|
|
400
400
|
_link = getattr(spec, "link", "identity")
|
|
401
401
|
if _link != "identity":
|
|
402
402
|
from bossanova.internal.maths.family.links import (
|
|
@@ -421,7 +421,7 @@ def compute_compound_bracket_contrasts(
|
|
|
421
421
|
focal_var=focal_var,
|
|
422
422
|
mee_type="means",
|
|
423
423
|
L_matrix=L_matrix,
|
|
424
|
-
|
|
424
|
+
effect_scale=effect_scale,
|
|
425
425
|
link=link_name,
|
|
426
426
|
)
|
|
427
427
|
|
{bossanova-0.1.0.dev15 → bossanova-0.1.0.dev17}/bossanova/internal/operations/marginal/compute.py
RENAMED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Routes parsed explore formulas to the appropriate computation: EMMs for
|
|
4
4
|
categorical focal variables, slopes for continuous, or contrasts.
|
|
5
|
-
Supports ``
|
|
5
|
+
Supports ``effect_scale=`` (link/response scale), ``how=`` (mem/ame),
|
|
6
|
+
and ``varying=`` (marginal/conditional).
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
from __future__ import annotations
|
|
@@ -70,7 +71,7 @@ def dispatch_marginal_computation(
|
|
|
70
71
|
Validates the focal variable, determines whether it is categorical or
|
|
71
72
|
continuous, and dispatches to the correct computation function.
|
|
72
73
|
|
|
73
|
-
Supports ``
|
|
74
|
+
Supports ``effect_scale=`` and ``varying=`` kwargs for scale transforms and
|
|
74
75
|
conditional (group-specific) effects in mixed models. When RHS conditions
|
|
75
76
|
contain bracket contrasts (e.g., ``Drug[A - B] ~ Dose[High - Low]``),
|
|
76
77
|
applies them as a post-processing step after the main computation.
|
|
@@ -80,11 +81,14 @@ def dispatch_marginal_computation(
|
|
|
80
81
|
bundle: DataBundle with model data and metadata.
|
|
81
82
|
fit: FitState with fitted coefficients.
|
|
82
83
|
data: The model's data DataFrame (for variable lookup and type detection).
|
|
83
|
-
spec: ModelSpec with link/family info (needed for
|
|
84
|
+
spec: ModelSpec with link/family info (needed for effect_scale="response").
|
|
84
85
|
formula_spec: FormulaSpec with learned encoding (needed for finite-diff slopes).
|
|
85
86
|
varying_offsets: VaryingState with BLUPs (needed for conditional effects).
|
|
86
87
|
**kwargs: Additional computation options. Recognized keys:
|
|
87
|
-
- ``
|
|
88
|
+
- ``how``: ``"auto"`` (default), ``"mem"`` (emmeans-style), or
|
|
89
|
+
``"ame"`` (g-computation / average marginal effect).
|
|
90
|
+
- ``effect_scale``: ``"link"`` (default) or ``"response"``
|
|
91
|
+
(inverse-link / data scale).
|
|
88
92
|
- ``varying``: ``"exclude"`` (default) or ``"include"`` (conditional).
|
|
89
93
|
- ``by``: Grouping variable for faceted effects.
|
|
90
94
|
- ``inverse_transforms``: ``True`` (default) to auto-resolve raw
|
|
@@ -160,7 +164,7 @@ def _dispatch_marginal_core(
|
|
|
160
164
|
compute_compound_bracket_contrasts,
|
|
161
165
|
)
|
|
162
166
|
|
|
163
|
-
|
|
167
|
+
effect_scale = str(kwargs.pop("effect_scale", "link"))
|
|
164
168
|
resolved = _resolve_all_conditions(parsed, bundle, data, kwargs, None, True)
|
|
165
169
|
return compute_compound_bracket_contrasts(
|
|
166
170
|
bundle,
|
|
@@ -169,7 +173,7 @@ def _dispatch_marginal_core(
|
|
|
169
173
|
parsed.contrast_expr,
|
|
170
174
|
data=data,
|
|
171
175
|
spec=spec,
|
|
172
|
-
|
|
176
|
+
effect_scale=effect_scale,
|
|
173
177
|
resolved=resolved,
|
|
174
178
|
)
|
|
175
179
|
|
|
@@ -180,15 +184,31 @@ def _dispatch_marginal_core(
|
|
|
180
184
|
# Validate focal variable is not the response
|
|
181
185
|
validate_focal_var(bundle, focal_var)
|
|
182
186
|
|
|
183
|
-
# Extract
|
|
184
|
-
|
|
185
|
-
if
|
|
186
|
-
raise ValueError(
|
|
187
|
+
# Extract effect_scale= and varying= from kwargs
|
|
188
|
+
effect_scale = str(kwargs.pop("effect_scale", "link"))
|
|
189
|
+
if effect_scale not in ("link", "response"):
|
|
190
|
+
raise ValueError(
|
|
191
|
+
f"effect_scale must be 'link' or 'response', got {effect_scale!r}"
|
|
192
|
+
)
|
|
187
193
|
|
|
188
194
|
varying = str(kwargs.pop("varying", "exclude"))
|
|
189
195
|
if varying not in ("exclude", "include"):
|
|
190
196
|
raise ValueError(f"varying must be 'exclude' or 'include', got {varying!r}")
|
|
191
197
|
|
|
198
|
+
# Extract how= kwarg with smart default
|
|
199
|
+
how_raw = kwargs.pop("how", "auto")
|
|
200
|
+
how_str = str(how_raw)
|
|
201
|
+
if how_str not in ("auto", "mem", "ame"):
|
|
202
|
+
raise ValueError(f"how must be 'auto', 'mem', or 'ame', got {how_str!r}")
|
|
203
|
+
if how_str == "auto":
|
|
204
|
+
# Smart default: "ame" for GLMs (non-identity link), "mem" otherwise
|
|
205
|
+
if spec is not None and spec.link != "identity":
|
|
206
|
+
how = "ame"
|
|
207
|
+
else:
|
|
208
|
+
how = "mem"
|
|
209
|
+
else:
|
|
210
|
+
how = how_str
|
|
211
|
+
|
|
192
212
|
# Extract inverse_transforms= kwarg (default True)
|
|
193
213
|
inverse_transforms = bool(kwargs.pop("inverse_transforms", True))
|
|
194
214
|
|
|
@@ -252,7 +272,8 @@ def _dispatch_marginal_core(
|
|
|
252
272
|
parsed.contrast_expr,
|
|
253
273
|
data=data,
|
|
254
274
|
spec=spec,
|
|
255
|
-
|
|
275
|
+
effect_scale=effect_scale,
|
|
276
|
+
how=how,
|
|
256
277
|
resolved=resolved,
|
|
257
278
|
)
|
|
258
279
|
|
|
@@ -266,7 +287,8 @@ def _dispatch_marginal_core(
|
|
|
266
287
|
parsed.contrast_degree,
|
|
267
288
|
data,
|
|
268
289
|
spec=spec,
|
|
269
|
-
|
|
290
|
+
effect_scale=effect_scale,
|
|
291
|
+
how=how,
|
|
270
292
|
resolved=resolved,
|
|
271
293
|
focal_at_values=parsed.focal_at_values,
|
|
272
294
|
contrast_ref=parsed.contrast_ref,
|
|
@@ -289,7 +311,8 @@ def _dispatch_marginal_core(
|
|
|
289
311
|
at_overrides=at_overrides,
|
|
290
312
|
set_categoricals=resolved.set_categoricals or None,
|
|
291
313
|
spec=spec,
|
|
292
|
-
|
|
314
|
+
effect_scale=effect_scale,
|
|
315
|
+
how=how,
|
|
293
316
|
)
|
|
294
317
|
# Continuous at-values (e.g. "Days@[0, 3, 6, 9]"): EMMs at
|
|
295
318
|
# specific values. Forward-transform the at-values through the
|
|
@@ -318,7 +341,7 @@ def _dispatch_marginal_core(
|
|
|
318
341
|
focal_var,
|
|
319
342
|
resolved=resolved,
|
|
320
343
|
spec=spec,
|
|
321
|
-
|
|
344
|
+
effect_scale=effect_scale,
|
|
322
345
|
)
|
|
323
346
|
if is_conditional and grouping_var is not None and varying_offsets is not None:
|
|
324
347
|
return compute_conditional_emm(
|
|
@@ -329,7 +352,7 @@ def _dispatch_marginal_core(
|
|
|
329
352
|
spec=spec,
|
|
330
353
|
varying_offsets=varying_offsets,
|
|
331
354
|
grouping_var=grouping_var,
|
|
332
|
-
|
|
355
|
+
effect_scale=effect_scale,
|
|
333
356
|
at_overrides=at_overrides,
|
|
334
357
|
set_categoricals=resolved.set_categoricals or None,
|
|
335
358
|
)
|
|
@@ -340,7 +363,8 @@ def _dispatch_marginal_core(
|
|
|
340
363
|
at_overrides=at_overrides,
|
|
341
364
|
set_categoricals=resolved.set_categoricals or None,
|
|
342
365
|
spec=spec,
|
|
343
|
-
|
|
366
|
+
effect_scale=effect_scale,
|
|
367
|
+
how=how,
|
|
344
368
|
)
|
|
345
369
|
|
|
346
370
|
# Continuous focal variable → slopes
|
|
@@ -353,7 +377,7 @@ def _dispatch_marginal_core(
|
|
|
353
377
|
spec=spec,
|
|
354
378
|
varying_offsets=varying_offsets,
|
|
355
379
|
grouping_var=grouping_var,
|
|
356
|
-
|
|
380
|
+
effect_scale=effect_scale,
|
|
357
381
|
)
|
|
358
382
|
|
|
359
383
|
# Crossed / conditioned slopes: conditions on RHS
|
|
@@ -378,7 +402,7 @@ def _dispatch_marginal_core(
|
|
|
378
402
|
data=data,
|
|
379
403
|
spec=spec,
|
|
380
404
|
formula_spec=fspec,
|
|
381
|
-
|
|
405
|
+
effect_scale=effect_scale,
|
|
382
406
|
)
|
|
383
407
|
|
|
384
408
|
return _compute_marginal_slope(
|
|
@@ -389,7 +413,8 @@ def _dispatch_marginal_core(
|
|
|
389
413
|
data=data,
|
|
390
414
|
spec=spec,
|
|
391
415
|
formula_spec=fspec,
|
|
392
|
-
|
|
416
|
+
effect_scale=effect_scale,
|
|
417
|
+
how=how,
|
|
393
418
|
)
|
|
394
419
|
|
|
395
420
|
|
|
@@ -548,7 +573,8 @@ def _compute_emm_categorical(
|
|
|
548
573
|
at_overrides: dict[str, float] | None = None,
|
|
549
574
|
set_categoricals: dict[str, str] | None = None,
|
|
550
575
|
spec: ModelSpec | None = None,
|
|
551
|
-
|
|
576
|
+
effect_scale: str = "link",
|
|
577
|
+
how: str = "mem",
|
|
552
578
|
) -> MeeState:
|
|
553
579
|
"""Compute EMMs for a categorical focal variable.
|
|
554
580
|
|
|
@@ -561,8 +587,9 @@ def _compute_emm_categorical(
|
|
|
561
587
|
at_overrides: Optional covariate overrides for conditioning.
|
|
562
588
|
set_categoricals: Optional dict pinning non-focal categoricals to
|
|
563
589
|
specific levels (e.g. ``{"Ethnicity": "Asian"}``).
|
|
564
|
-
spec: ModelSpec with link info (for
|
|
565
|
-
|
|
590
|
+
spec: ModelSpec with link info (for effect_scale="response").
|
|
591
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
592
|
+
how: Averaging method: ``"mem"`` or ``"ame"``.
|
|
566
593
|
|
|
567
594
|
Returns:
|
|
568
595
|
MeeState with grid of levels and their estimated means.
|
|
@@ -576,7 +603,8 @@ def _compute_emm_categorical(
|
|
|
576
603
|
at_overrides=at_overrides,
|
|
577
604
|
set_categoricals=set_categoricals,
|
|
578
605
|
spec=spec,
|
|
579
|
-
|
|
606
|
+
effect_scale=effect_scale,
|
|
607
|
+
how=how,
|
|
580
608
|
)
|
|
581
609
|
|
|
582
610
|
|
|
@@ -587,7 +615,7 @@ def _compute_emm_crossed(
|
|
|
587
615
|
*,
|
|
588
616
|
resolved: ResolvedConditions,
|
|
589
617
|
spec: ModelSpec | None = None,
|
|
590
|
-
|
|
618
|
+
effect_scale: str = "link",
|
|
591
619
|
) -> MeeState:
|
|
592
620
|
"""Compute crossed EMMs over focal levels x condition grid.
|
|
593
621
|
|
|
@@ -599,8 +627,8 @@ def _compute_emm_crossed(
|
|
|
599
627
|
fit: FitState with fitted coefficients.
|
|
600
628
|
focal_var: Name of the categorical focal variable.
|
|
601
629
|
resolved: ResolvedConditions with grid and scalar conditions.
|
|
602
|
-
spec: ModelSpec with link info (for
|
|
603
|
-
|
|
630
|
+
spec: ModelSpec with link info (for effect_scale="response").
|
|
631
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
604
632
|
|
|
605
633
|
Returns:
|
|
606
634
|
MeeState with ``n_focal x n_grid`` rows and condition columns.
|
|
@@ -681,7 +709,7 @@ def _compute_emm_crossed(
|
|
|
681
709
|
estimates, L_matrix = estimates_link, X_ref
|
|
682
710
|
link_name: str | None = None
|
|
683
711
|
L_matrix_link: np.ndarray | None = None
|
|
684
|
-
if
|
|
712
|
+
if effect_scale == "response" and spec is not None and spec.link != "identity":
|
|
685
713
|
from bossanova.internal.maths.family.links import (
|
|
686
714
|
apply_link_inverse,
|
|
687
715
|
apply_link_inverse_deriv,
|
|
@@ -705,7 +733,8 @@ def _compute_emm_crossed(
|
|
|
705
733
|
explore_formula=f"{focal_var}{cond_str}",
|
|
706
734
|
focal_var=focal_var,
|
|
707
735
|
mee_type="means",
|
|
708
|
-
|
|
736
|
+
effect_scale=effect_scale,
|
|
737
|
+
how="mem",
|
|
709
738
|
L_matrix=L_matrix,
|
|
710
739
|
link=link_name,
|
|
711
740
|
L_matrix_link=L_matrix_link,
|
|
@@ -778,7 +807,8 @@ def _compute_marginal_slope(
|
|
|
778
807
|
data: pl.DataFrame,
|
|
779
808
|
spec: ModelSpec | None = None,
|
|
780
809
|
formula_spec: FormulaSpec | None = None,
|
|
781
|
-
|
|
810
|
+
effect_scale: str = "link",
|
|
811
|
+
how: str = "mem",
|
|
782
812
|
) -> MeeState:
|
|
783
813
|
"""Compute marginal slope for a continuous focal variable.
|
|
784
814
|
|
|
@@ -796,7 +826,8 @@ def _compute_marginal_slope(
|
|
|
796
826
|
data: Raw model data DataFrame.
|
|
797
827
|
spec: ModelSpec with family/link info.
|
|
798
828
|
formula_spec: FormulaSpec with learned encoding (for finite-diff).
|
|
799
|
-
|
|
829
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
830
|
+
how: Averaging method: ``"mem"`` or ``"ame"``.
|
|
800
831
|
|
|
801
832
|
Returns:
|
|
802
833
|
MeeState with marginal slope estimate.
|
|
@@ -824,7 +855,8 @@ def _compute_marginal_slope(
|
|
|
824
855
|
spec=spec,
|
|
825
856
|
formula_spec=formula_spec,
|
|
826
857
|
data=data,
|
|
827
|
-
|
|
858
|
+
effect_scale=effect_scale,
|
|
859
|
+
how=how,
|
|
828
860
|
)
|
|
829
861
|
|
|
830
862
|
# Fast path: coefficient extraction — use resolved name
|
|
@@ -834,7 +866,7 @@ def _compute_marginal_slope(
|
|
|
834
866
|
focal_var=coef_var,
|
|
835
867
|
explore_formula=focal_var,
|
|
836
868
|
spec=spec,
|
|
837
|
-
|
|
869
|
+
effect_scale=effect_scale,
|
|
838
870
|
)
|
|
839
871
|
|
|
840
872
|
|
|
@@ -1020,7 +1052,8 @@ def _compute_contrasts(
|
|
|
1020
1052
|
data: pl.DataFrame,
|
|
1021
1053
|
*,
|
|
1022
1054
|
spec: ModelSpec | None = None,
|
|
1023
|
-
|
|
1055
|
+
effect_scale: str = "link",
|
|
1056
|
+
how: str = "mem",
|
|
1024
1057
|
resolved: ResolvedConditions | None = None,
|
|
1025
1058
|
focal_at_values: tuple[float | str, ...] | None = None,
|
|
1026
1059
|
contrast_ref: str | None = None,
|
|
@@ -1030,7 +1063,7 @@ def _compute_contrasts(
|
|
|
1030
1063
|
First computes EMMs, then applies the requested contrast matrix.
|
|
1031
1064
|
When ``resolved`` contains grid conditions, computes crossed EMMs and
|
|
1032
1065
|
applies grouped contrasts. When ``focal_at_values`` is provided
|
|
1033
|
-
(e.g. from ``pairwise(cyl[4, 8])``), contrasts are computed only
|
|
1066
|
+
(e.g. from ``pairwise(cyl@[4, 8])``), contrasts are computed only
|
|
1034
1067
|
over the requested subset of levels.
|
|
1035
1068
|
|
|
1036
1069
|
Args:
|
|
@@ -1041,8 +1074,9 @@ def _compute_contrasts(
|
|
|
1041
1074
|
sum, helmert).
|
|
1042
1075
|
contrast_degree: Degree for polynomial contrasts (None = max).
|
|
1043
1076
|
data: Model data for level extraction.
|
|
1044
|
-
spec: ModelSpec with link info (for
|
|
1045
|
-
|
|
1077
|
+
spec: ModelSpec with link info (for effect_scale="response").
|
|
1078
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
1079
|
+
how: Averaging method: ``"mem"`` or ``"ame"``.
|
|
1046
1080
|
resolved: Resolved conditions for conditioning.
|
|
1047
1081
|
focal_at_values: Optional subset of levels from at-spec syntax
|
|
1048
1082
|
(e.g. ``pairwise(cyl@[4, 8])``).
|
|
@@ -1088,7 +1122,7 @@ def _compute_contrasts(
|
|
|
1088
1122
|
focal_var,
|
|
1089
1123
|
resolved=resolved,
|
|
1090
1124
|
spec=spec,
|
|
1091
|
-
|
|
1125
|
+
effect_scale=effect_scale,
|
|
1092
1126
|
)
|
|
1093
1127
|
if contrast_ref is not None:
|
|
1094
1128
|
ref_idx = _resolve_ref_idx(emm_state.grid)
|
|
@@ -1112,7 +1146,8 @@ def _compute_contrasts(
|
|
|
1112
1146
|
at_overrides=at_overrides,
|
|
1113
1147
|
set_categoricals=set_cats,
|
|
1114
1148
|
spec=spec,
|
|
1115
|
-
|
|
1149
|
+
effect_scale=effect_scale,
|
|
1150
|
+
how=how,
|
|
1116
1151
|
)
|
|
1117
1152
|
if contrast_ref is not None:
|
|
1118
1153
|
ref_idx = _resolve_ref_idx(emm_state.grid)
|
|
@@ -1129,7 +1164,8 @@ def _compute_bracket_contrasts(
|
|
|
1129
1164
|
*,
|
|
1130
1165
|
data: pl.DataFrame,
|
|
1131
1166
|
spec: ModelSpec | None = None,
|
|
1132
|
-
|
|
1167
|
+
effect_scale: str = "link",
|
|
1168
|
+
how: str = "mem",
|
|
1133
1169
|
resolved: ResolvedConditions | None = None,
|
|
1134
1170
|
) -> MeeState:
|
|
1135
1171
|
"""Compute bracket contrast expression for a categorical focal variable.
|
|
@@ -1144,8 +1180,9 @@ def _compute_bracket_contrasts(
|
|
|
1144
1180
|
focal_var: Name of the categorical variable.
|
|
1145
1181
|
contrast_expr: ContrastExpr AST from the parser.
|
|
1146
1182
|
data: Model data DataFrame.
|
|
1147
|
-
spec: ModelSpec with link info (for
|
|
1148
|
-
|
|
1183
|
+
spec: ModelSpec with link info (for effect_scale="response").
|
|
1184
|
+
effect_scale: Scale of estimates: ``"link"`` or ``"response"``.
|
|
1185
|
+
how: Averaging method: ``"mem"`` or ``"ame"``.
|
|
1149
1186
|
resolved: Resolved conditions for conditioning.
|
|
1150
1187
|
|
|
1151
1188
|
Returns:
|
|
@@ -1163,7 +1200,7 @@ def _compute_bracket_contrasts(
|
|
|
1163
1200
|
focal_var,
|
|
1164
1201
|
resolved=resolved,
|
|
1165
1202
|
spec=spec,
|
|
1166
|
-
|
|
1203
|
+
effect_scale=effect_scale,
|
|
1167
1204
|
)
|
|
1168
1205
|
return apply_bracket_contrasts_grouped(emm_state, contrast_expr)
|
|
1169
1206
|
|
|
@@ -1178,6 +1215,7 @@ def _compute_bracket_contrasts(
|
|
|
1178
1215
|
at_overrides=at_overrides,
|
|
1179
1216
|
set_categoricals=set_cats,
|
|
1180
1217
|
spec=spec,
|
|
1181
|
-
|
|
1218
|
+
effect_scale=effect_scale,
|
|
1219
|
+
how=how,
|
|
1182
1220
|
)
|
|
1183
1221
|
return apply_bracket_contrasts(emm_state, contrast_expr)
|