bossanova 0.1.0.dev14__tar.gz → 0.1.0.dev15__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.dev14 → bossanova-0.1.0.dev15}/PKG-INFO +1 -1
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/__init__.py +4 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/state.py +2 -1
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/explore.py +88 -6
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/state.py +20 -4
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/__init__.py +3 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/config.py +56 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/contrasts.py +107 -7
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/multiplicity.py +3 -2
- bossanova-0.1.0.dev15/bossanova/internal/maths/rounding.py +89 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/common/__init__.py +14 -0
- bossanova-0.1.0.dev15/bossanova/internal/operations/common/contrast_registry.py +61 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/compare.py +11 -7
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/__init__.py +12 -0
- bossanova-0.1.0.dev15/bossanova/internal/operations/marginal/bracket_contrasts.py +565 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/compute.py +185 -4
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/conditions.py +43 -1
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/contrasts.py +146 -16
- bossanova-0.1.0.dev15/bossanova/internal/operations/marginal/explore.py +173 -0
- bossanova-0.1.0.dev15/bossanova/internal/operations/marginal/explore_parser.py +754 -0
- bossanova-0.1.0.dev15/bossanova/internal/operations/marginal/explore_scanner.py +81 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/inference.py +11 -8
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/mem.py +1 -4
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/model/core.py +145 -29
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/model/summary.py +30 -30
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/pyproject.toml +1 -1
- bossanova-0.1.0.dev14/bossanova/internal/operations/marginal/explore.py +0 -494
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/.gitignore +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/LICENSE +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/README.md +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/README.md +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/advertising.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/cake.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/chickweight.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/credit.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/gammas.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/mtcars.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/penguins.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/poker.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/sleep.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/titanic.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/titanic_test.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/data/titanic_train.csv +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/distributions/continuous.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/distributions/discrete.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/distributions/varying.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/expressions.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/data.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/dataframes.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/resamples.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/results.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/specs.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/schemas.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/data.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/display.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/formula.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/specs.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/validators.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/backend/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/backend/dispatch.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/backend/jax.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/backend/numpy.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/backend/protocol.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/batching.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/convergence.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/design/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/design/coding.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/design/names.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/design/reference.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/design/z_matrix.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/differentiation.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/algebra.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/base.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/core.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/derived.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/factories.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/plotting.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/distributions/probability.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/binomial.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/create.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/gamma.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/gaussian.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/links.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/poisson.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/response.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/schema.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/family/tdist.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/diagnostics.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/estimation.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/hypothesis.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/information_criteria.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/profile.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/sandwich.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/satterthwaite.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/wald_variance.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/welch.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/linalg/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/linalg/qr.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/linalg/schur.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/linalg/sparse.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/linalg/svd.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/predict.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/rng.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/glm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/glmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/heuristics.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/initialization.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/lambda_builder.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/lambda_sparse.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/lambda_template.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/lmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/optimize.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/pirls_sparse.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/solvers/quadrature.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/tolerances.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/transforms.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/variance.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/weights.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/bundle.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/common/data_utils.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/common/factors.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/common/formula_utils.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/cv.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/deviance.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/f_test.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/helpers.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/lrt.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/lrt_compare.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/compare/refit.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/contrasts.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/convergence.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/diagnostics.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/dispatch.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/glm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/glmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/lmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/ols.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/fit/rank.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/design.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/encoding.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/evaluate.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/evaluate_newdata.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/evaluate_transforms.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/helpers.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parse.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parser/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parser/expr.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parser/parser.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parser/scanner.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/parser/token.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/formula/random_effects.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/asymptotic.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/bootstrap.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/cv.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/mee.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/params.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/permutation.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/prediction.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/profile.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/resample_bundle.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/satterthwaite_emm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/infer/simulation.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/emm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/grid.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/joint_tests.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/slopes.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/marginal/validation.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/predict.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/profile.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/rendering/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/rendering/latex.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/common.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/core.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/glm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/glmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/lm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/lm_bca.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/lm_operators.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/lmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/mixed.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/results.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/resample/utils.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/generate.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/glm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/glmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/lm.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/dgp/lmer.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/harness.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/metrics.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/model_sim.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/simulation/power.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/transforms.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/varying.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/README.md +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/cognition.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/compare.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/core.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/core_data.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/core_protocols.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/core_sizing.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/core_viz.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/dag.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/design.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/fit.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/fit_builders.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/fit_layers.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/helpers.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/lattice.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/layout.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/params.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/predict.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/profile.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/ranef.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/relationships.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/resamples.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/resid.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/viz/vif.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/model/__init__.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/model/guards.py +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/py.typed +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/tests/bossanova_benchmarks/bootstrap/data/README.md +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/tests/bossanova_benchmarks/insteval/data/README.md +0 -0
- {bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/tests/bossanova_tests/hypothesis/README.md +0 -0
|
@@ -15,7 +15,9 @@ except (ImportError, AttributeError):
|
|
|
15
15
|
|
|
16
16
|
# Configuration
|
|
17
17
|
from bossanova.internal.maths.config import ( # noqa: E402
|
|
18
|
+
get_display_digits,
|
|
18
19
|
get_singular_tolerance,
|
|
20
|
+
set_display_digits,
|
|
19
21
|
set_singular_tolerance,
|
|
20
22
|
)
|
|
21
23
|
|
|
@@ -42,11 +44,13 @@ __all__ = [
|
|
|
42
44
|
"compare",
|
|
43
45
|
"expressions",
|
|
44
46
|
"get_backend",
|
|
47
|
+
"get_display_digits",
|
|
45
48
|
"get_singular_tolerance",
|
|
46
49
|
"load_dataset",
|
|
47
50
|
"lrt",
|
|
48
51
|
"model",
|
|
49
52
|
"set_backend",
|
|
53
|
+
"set_display_digits",
|
|
50
54
|
"set_singular_tolerance",
|
|
51
55
|
"show_datasets",
|
|
52
56
|
"viz",
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/builders/state.py
RENAMED
|
@@ -222,7 +222,8 @@ def build_mee_state(
|
|
|
222
222
|
L_matrix: Design matrix for delta method inference (optional).
|
|
223
223
|
Shape (n_estimates, n_coef). For EMMs this is X_ref.
|
|
224
224
|
contrast_method: Original contrast type for multiplicity adjustment
|
|
225
|
-
("pairwise", "
|
|
225
|
+
("pairwise", "sequential", "poly", "treatment", "sum",
|
|
226
|
+
"helmert", or None).
|
|
226
227
|
n_contrast_levels: Number of EMM levels before contrasting (family size).
|
|
227
228
|
link: Link function name for response-scale CI back-transformation.
|
|
228
229
|
L_matrix_link: Link-scale L_matrix for CI back-transformation.
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/explore.py
RENAMED
|
@@ -4,29 +4,93 @@ from attrs import field, frozen, validators
|
|
|
4
4
|
|
|
5
5
|
__all__ = [
|
|
6
6
|
"Condition",
|
|
7
|
+
"ContrastExpr",
|
|
8
|
+
"ContrastItem",
|
|
9
|
+
"ContrastOperand",
|
|
7
10
|
"ExploreFormula",
|
|
8
11
|
"ExploreFormulaError",
|
|
9
12
|
]
|
|
10
13
|
|
|
11
14
|
|
|
15
|
+
# =====================================================================
|
|
16
|
+
# Bracket contrast expression containers
|
|
17
|
+
# =====================================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@frozen
|
|
21
|
+
class ContrastOperand:
|
|
22
|
+
"""One side of a bracket contrast item.
|
|
23
|
+
|
|
24
|
+
Represents a single operand in a contrast like ``A - B`` or
|
|
25
|
+
``(A + B) - C``.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
levels: Level names for this operand. Empty tuple for wildcard.
|
|
29
|
+
Multiple levels indicate a grouped mean (e.g., ``(A + B)``
|
|
30
|
+
produces ``levels=("A", "B")``).
|
|
31
|
+
is_wildcard: True for the ``*`` operator, which expands to all
|
|
32
|
+
levels not mentioned on the other side.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
levels: tuple[str, ...] = field(factory=tuple, converter=tuple)
|
|
36
|
+
is_wildcard: bool = field(default=False, validator=validators.instance_of(bool))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@frozen
|
|
40
|
+
class ContrastItem:
|
|
41
|
+
"""A single contrast: left operand minus right operand.
|
|
42
|
+
|
|
43
|
+
Represents one ``left - right`` comparison in a bracket contrast
|
|
44
|
+
expression like ``Drug[Active - Placebo]``.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
left: Left operand (positive side).
|
|
48
|
+
right: Right operand (negative side).
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
left: ContrastOperand = field(validator=validators.instance_of(ContrastOperand))
|
|
52
|
+
right: ContrastOperand = field(validator=validators.instance_of(ContrastOperand))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@frozen
|
|
56
|
+
class ContrastExpr:
|
|
57
|
+
"""Bracket contrast expression: ``Drug[A - B, C - D]``.
|
|
58
|
+
|
|
59
|
+
Represents a complete bracket contrast specification parsed from
|
|
60
|
+
explore formula syntax.
|
|
61
|
+
|
|
62
|
+
Attributes:
|
|
63
|
+
var: Variable name (e.g., ``"Drug"``).
|
|
64
|
+
items: Tuple of contrast items to compute.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
var: str = field(validator=validators.instance_of(str))
|
|
68
|
+
items: tuple[ContrastItem, ...] = field(converter=tuple)
|
|
69
|
+
|
|
70
|
+
|
|
12
71
|
@frozen
|
|
13
72
|
class Condition:
|
|
14
73
|
"""A conditioning specification in explore formula.
|
|
15
74
|
|
|
16
|
-
Represents a variable to condition on, optionally with specific values
|
|
17
|
-
|
|
75
|
+
Represents a variable to condition on, optionally with specific values,
|
|
76
|
+
a method for generating values, or a bracket contrast expression.
|
|
18
77
|
|
|
19
78
|
Attributes:
|
|
20
79
|
var: Variable name to condition on.
|
|
21
80
|
at_values: Specific values to evaluate at (e.g., (50.0,) or ("A", "B")).
|
|
22
81
|
at_range: Number of evenly-spaced values across the variable's range.
|
|
23
82
|
at_quantile: Number of quantile values to use.
|
|
83
|
+
contrast_expr: Bracket contrast expression on this condition variable
|
|
84
|
+
(e.g., from ``Dose[High - Low]`` on the RHS). When set, the
|
|
85
|
+
variable is treated as a grid categorical during condition
|
|
86
|
+
resolution, and the contrast is applied as a post-processing step.
|
|
24
87
|
"""
|
|
25
88
|
|
|
26
89
|
var: str = field(validator=validators.instance_of(str))
|
|
27
90
|
at_values: tuple | None = field(default=None)
|
|
28
91
|
at_range: int | None = field(default=None)
|
|
29
92
|
at_quantile: int | None = field(default=None)
|
|
93
|
+
contrast_expr: ContrastExpr | None = field(default=None)
|
|
30
94
|
|
|
31
95
|
|
|
32
96
|
@frozen
|
|
@@ -38,10 +102,16 @@ class ExploreFormula:
|
|
|
38
102
|
|
|
39
103
|
Attributes:
|
|
40
104
|
focal_var: The variable to compute marginal effects for.
|
|
41
|
-
contrast_type: Type of contrast (pairwise,
|
|
42
|
-
or None for simple EMMs.
|
|
105
|
+
contrast_type: Type of contrast (pairwise, sequential, poly, treatment,
|
|
106
|
+
sum, helmert, custom) or None for simple EMMs. Set to ``"custom"``
|
|
107
|
+
for bracket contrast expressions.
|
|
43
108
|
contrast_degree: Degree parameter for polynomial contrasts (default None
|
|
44
109
|
means use n_levels - 1, i.e., maximum degree).
|
|
110
|
+
contrast_ref: Reference level for treatment/dummy contrasts
|
|
111
|
+
(e.g., ``"Placebo"`` from ``treatment(Drug, ref=Placebo)``).
|
|
112
|
+
contrast_expr: Bracket contrast expression AST (e.g., from
|
|
113
|
+
``Drug[Active - Placebo]`` syntax). None for named contrast
|
|
114
|
+
functions or simple EMMs.
|
|
45
115
|
conditions: Tuple of Condition objects specifying conditioning variables.
|
|
46
116
|
focal_at_values: Specific values to evaluate the focal variable at
|
|
47
117
|
(e.g., from ``Days@[0, 3, 6, 9]`` syntax). None means use all levels.
|
|
@@ -54,6 +124,8 @@ class ExploreFormula:
|
|
|
54
124
|
focal_var: str = field(validator=validators.instance_of(str))
|
|
55
125
|
contrast_type: str | None = field(default=None)
|
|
56
126
|
contrast_degree: int | None = field(default=None)
|
|
127
|
+
contrast_ref: str | None = field(default=None)
|
|
128
|
+
contrast_expr: ContrastExpr | None = field(default=None)
|
|
57
129
|
conditions: tuple[Condition, ...] = field(factory=tuple, converter=tuple)
|
|
58
130
|
focal_at_values: tuple[float | str, ...] | None = field(default=None)
|
|
59
131
|
focal_at_range: int | None = field(default=None)
|
|
@@ -82,14 +154,24 @@ class ExploreFormula:
|
|
|
82
154
|
|
|
83
155
|
@property
|
|
84
156
|
def has_contrast(self) -> bool:
|
|
85
|
-
"""Return True if
|
|
86
|
-
return self.contrast_type is not None
|
|
157
|
+
"""Return True if any contrast is specified (named function or bracket expr)."""
|
|
158
|
+
return self.contrast_type is not None or self.contrast_expr is not None
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def has_contrast_expr(self) -> bool:
|
|
162
|
+
"""Return True if a bracket contrast expression is specified."""
|
|
163
|
+
return self.contrast_expr is not None
|
|
87
164
|
|
|
88
165
|
@property
|
|
89
166
|
def has_conditions(self) -> bool:
|
|
90
167
|
"""Return True if conditioning variables are specified."""
|
|
91
168
|
return len(self.conditions) > 0
|
|
92
169
|
|
|
170
|
+
@property
|
|
171
|
+
def has_rhs_contrasts(self) -> bool:
|
|
172
|
+
"""Return True if any RHS condition has a bracket contrast expression."""
|
|
173
|
+
return any(c.contrast_expr is not None for c in self.conditions)
|
|
174
|
+
|
|
93
175
|
|
|
94
176
|
class ExploreFormulaError(ValueError):
|
|
95
177
|
"""Error in explore formula syntax.
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/containers/structs/state.py
RENAMED
|
@@ -219,13 +219,18 @@ 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
|
+
weights: Averaging philosophy used: ``"equal"`` (balanced reference grid,
|
|
223
|
+
emmeans-style) or ``"observed"`` (g-computation over observed data).
|
|
222
224
|
L_matrix: Design matrix for delta method inference. Shape (n_estimates, n_coef).
|
|
223
225
|
For EMMs, this is X_ref; for slopes, a coefficient selector row.
|
|
224
226
|
contrast_method: Original contrast type for multiplicity adjustment
|
|
225
|
-
("pairwise", "
|
|
227
|
+
("pairwise", "sequential", "poly", "treatment", "sum",
|
|
228
|
+
"helmert", or None).
|
|
226
229
|
n_contrast_levels: Number of EMM levels before contrasting (family size for Tukey).
|
|
227
|
-
link: Link function name for response-scale back-transformation (set when units="data"
|
|
228
|
-
|
|
230
|
+
link: Link function name for response-scale back-transformation (set when units="data"
|
|
231
|
+
and weights="equal").
|
|
232
|
+
L_matrix_link: Link-scale L_matrix for CI back-transformation (set when units="data"
|
|
233
|
+
and weights="equal").
|
|
229
234
|
inference_method: Inference method used (``"asymp"``, ``"boot"``,
|
|
230
235
|
``"perm"``, or ``None``). Controls which columns appear in
|
|
231
236
|
the ``.effects`` DataFrame.
|
|
@@ -253,6 +258,7 @@ class MeeState:
|
|
|
253
258
|
focal_var: str = field(validator=validators.instance_of(str))
|
|
254
259
|
type: str = field(validator=validators.in_(("means", "slopes", "contrasts")))
|
|
255
260
|
units: str = field(default="link", validator=validators.in_(("link", "data")))
|
|
261
|
+
weights: str = field(default="equal", validator=validators.in_(("equal", "observed")))
|
|
256
262
|
|
|
257
263
|
# Design matrix for delta method inference (optional)
|
|
258
264
|
# Shape: (n_estimates, n_coef). For EMMs, this is X_ref; for slopes, a selector row.
|
|
@@ -264,7 +270,17 @@ class MeeState:
|
|
|
264
270
|
contrast_method: str | None = field(
|
|
265
271
|
default=None,
|
|
266
272
|
validator=validators.optional(
|
|
267
|
-
validators.in_(
|
|
273
|
+
validators.in_(
|
|
274
|
+
(
|
|
275
|
+
"pairwise",
|
|
276
|
+
"sequential",
|
|
277
|
+
"poly",
|
|
278
|
+
"treatment",
|
|
279
|
+
"sum",
|
|
280
|
+
"helmert",
|
|
281
|
+
"custom",
|
|
282
|
+
)
|
|
283
|
+
)
|
|
268
284
|
),
|
|
269
285
|
)
|
|
270
286
|
n_contrast_levels: int | None = field(default=None)
|
|
@@ -28,6 +28,7 @@ from bossanova.internal.maths.batching import (
|
|
|
28
28
|
get_available_memory_gb,
|
|
29
29
|
)
|
|
30
30
|
from bossanova.internal.maths.config import is_singular
|
|
31
|
+
from bossanova.internal.maths.rounding import round_float_columns, round_sigfigs
|
|
31
32
|
from bossanova.internal.maths.inference import (
|
|
32
33
|
Chi2TestResult,
|
|
33
34
|
FTestResult,
|
|
@@ -240,6 +241,8 @@ __all__ = [
|
|
|
240
241
|
"poly_numeric",
|
|
241
242
|
"poly_numeric_labels",
|
|
242
243
|
"qr_solve",
|
|
244
|
+
"round_float_columns",
|
|
245
|
+
"round_sigfigs",
|
|
243
246
|
"sequential_contrast",
|
|
244
247
|
"sequential_labels",
|
|
245
248
|
"sum_contrast",
|
|
@@ -12,15 +12,71 @@ if TYPE_CHECKING:
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
|
+
"get_display_digits",
|
|
15
16
|
"get_singular_tolerance",
|
|
16
17
|
"is_singular",
|
|
18
|
+
"set_display_digits",
|
|
17
19
|
"set_singular_tolerance",
|
|
18
20
|
]
|
|
19
21
|
|
|
22
|
+
# Default significant figures for DataFrame display output.
|
|
23
|
+
# Matches R's summary() convention of 4 significant digits.
|
|
24
|
+
_DISPLAY_DIGITS: int = 4
|
|
25
|
+
|
|
20
26
|
# Default singular tolerance matches lme4's default (utilities.R:924-928)
|
|
21
27
|
_SINGULAR_TOLERANCE: float = 1e-4
|
|
22
28
|
|
|
23
29
|
|
|
30
|
+
def get_display_digits() -> int:
|
|
31
|
+
"""Get the number of significant figures for DataFrame display output.
|
|
32
|
+
|
|
33
|
+
Controls how many significant figures are shown in user-facing
|
|
34
|
+
DataFrames returned by model properties (``.params``, ``.effects``,
|
|
35
|
+
``.diagnostics``, etc.) and ``compare()``. Matches R's ``signif()``
|
|
36
|
+
convention.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Current display digits setting (default 4).
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
```python
|
|
43
|
+
from bossanova import get_display_digits
|
|
44
|
+
get_display_digits()
|
|
45
|
+
# 4
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
48
|
+
return _DISPLAY_DIGITS
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def set_display_digits(digits: int) -> None:
|
|
52
|
+
"""Set the number of significant figures for DataFrame display output.
|
|
53
|
+
|
|
54
|
+
Controls how many significant figures are shown in user-facing
|
|
55
|
+
DataFrames returned by model properties (``.params``, ``.effects``,
|
|
56
|
+
``.diagnostics``, etc.) and ``compare()``. Matches R's ``signif()``
|
|
57
|
+
convention.
|
|
58
|
+
|
|
59
|
+
The ``summary()`` method has its own ``digits`` parameter and is
|
|
60
|
+
unaffected by this setting.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
digits: Number of significant figures. Must be >= 1.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
ValueError: If digits is less than 1.
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
```python
|
|
70
|
+
from bossanova import set_display_digits
|
|
71
|
+
set_display_digits(6) # Show 6 significant figures
|
|
72
|
+
```
|
|
73
|
+
"""
|
|
74
|
+
global _DISPLAY_DIGITS
|
|
75
|
+
if digits < 1:
|
|
76
|
+
raise ValueError(f"digits must be >= 1, got {digits}")
|
|
77
|
+
_DISPLAY_DIGITS = digits
|
|
78
|
+
|
|
79
|
+
|
|
24
80
|
def get_singular_tolerance() -> float:
|
|
25
81
|
"""Get the current singular tolerance for mixed models.
|
|
26
82
|
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/contrasts.py
RENAMED
|
@@ -7,9 +7,11 @@ import numpy as np
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"build_all_pairwise_contrast",
|
|
9
9
|
"build_contrast_matrix",
|
|
10
|
+
"build_helmert_contrast",
|
|
10
11
|
"build_pairwise_contrast",
|
|
11
12
|
"build_sequential_contrast",
|
|
12
13
|
"build_sum_to_zero_contrast",
|
|
14
|
+
"build_treatment_contrast",
|
|
13
15
|
"compose_contrast",
|
|
14
16
|
"get_contrast_labels",
|
|
15
17
|
]
|
|
@@ -224,6 +226,98 @@ def build_sum_to_zero_contrast(n_levels: int) -> np.ndarray:
|
|
|
224
226
|
return C
|
|
225
227
|
|
|
226
228
|
|
|
229
|
+
def build_treatment_contrast(n_levels: int, ref_idx: int = 0) -> np.ndarray:
|
|
230
|
+
"""Build treatment (Dunnett-style) contrasts against a reference level.
|
|
231
|
+
|
|
232
|
+
Creates n_levels - 1 contrasts, each comparing one non-reference level
|
|
233
|
+
to the specified reference level.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
n_levels: Number of EMM levels (factor levels).
|
|
237
|
+
ref_idx: Index of the reference level (0-based).
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Contrast matrix of shape (n_levels - 1, n_levels).
|
|
241
|
+
Row i compares non-reference level i to the reference.
|
|
242
|
+
|
|
243
|
+
Raises:
|
|
244
|
+
ValueError: If n_levels < 1 or ref_idx out of range.
|
|
245
|
+
|
|
246
|
+
Examples:
|
|
247
|
+
>>> C = build_treatment_contrast(3, ref_idx=0)
|
|
248
|
+
>>> C
|
|
249
|
+
array([[-1., 1., 0.],
|
|
250
|
+
[-1., 0., 1.]])
|
|
251
|
+
|
|
252
|
+
>>> C = build_treatment_contrast(3, ref_idx=2)
|
|
253
|
+
>>> C
|
|
254
|
+
array([[ 1., 0., -1.],
|
|
255
|
+
[ 0., 1., -1.]])
|
|
256
|
+
"""
|
|
257
|
+
if n_levels < 1:
|
|
258
|
+
raise ValueError(f"n_levels must be >= 1, got {n_levels}")
|
|
259
|
+
if ref_idx < 0 or ref_idx >= n_levels:
|
|
260
|
+
raise ValueError(f"ref_idx must be in [0, {n_levels - 1}], got {ref_idx}")
|
|
261
|
+
|
|
262
|
+
if n_levels == 1:
|
|
263
|
+
return np.zeros((0, 1))
|
|
264
|
+
|
|
265
|
+
C = np.zeros((n_levels - 1, n_levels))
|
|
266
|
+
row = 0
|
|
267
|
+
for i in range(n_levels):
|
|
268
|
+
if i == ref_idx:
|
|
269
|
+
continue
|
|
270
|
+
C[row, ref_idx] = -1
|
|
271
|
+
C[row, i] = 1
|
|
272
|
+
row += 1
|
|
273
|
+
|
|
274
|
+
return C
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def build_helmert_contrast(n_levels: int) -> np.ndarray:
|
|
278
|
+
"""Build Helmert contrasts (each level vs mean of previous levels).
|
|
279
|
+
|
|
280
|
+
Creates n_levels - 1 contrasts where level k is compared to
|
|
281
|
+
the mean of levels 0, 1, ..., k-1. Useful for ordered factors
|
|
282
|
+
where you want to test if each successive level differs from
|
|
283
|
+
the average of all prior levels.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
n_levels: Number of EMM levels (factor levels).
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Contrast matrix of shape (n_levels - 1, n_levels).
|
|
290
|
+
|
|
291
|
+
Raises:
|
|
292
|
+
ValueError: If n_levels < 1.
|
|
293
|
+
|
|
294
|
+
Examples:
|
|
295
|
+
>>> C = build_helmert_contrast(3)
|
|
296
|
+
>>> C
|
|
297
|
+
array([[-1. , 1. , 0. ],
|
|
298
|
+
[-0.5, -0.5, 1. ]])
|
|
299
|
+
|
|
300
|
+
>>> C = build_helmert_contrast(4)
|
|
301
|
+
>>> C
|
|
302
|
+
array([[-1. , 1. , 0. , 0. ],
|
|
303
|
+
[-0.5 , -0.5 , 1. , 0. ],
|
|
304
|
+
[-0.33333333, -0.33333333, -0.33333333, 1. ]])
|
|
305
|
+
"""
|
|
306
|
+
if n_levels < 1:
|
|
307
|
+
raise ValueError(f"n_levels must be >= 1, got {n_levels}")
|
|
308
|
+
|
|
309
|
+
if n_levels == 1:
|
|
310
|
+
return np.zeros((0, 1))
|
|
311
|
+
|
|
312
|
+
C = np.zeros((n_levels - 1, n_levels))
|
|
313
|
+
for k in range(1, n_levels):
|
|
314
|
+
# Level k vs mean of levels 0..k-1
|
|
315
|
+
C[k - 1, :k] = -1.0 / k
|
|
316
|
+
C[k - 1, k] = 1.0
|
|
317
|
+
|
|
318
|
+
return C
|
|
319
|
+
|
|
320
|
+
|
|
227
321
|
def build_contrast_matrix(
|
|
228
322
|
contrast_type: str | dict,
|
|
229
323
|
levels: list,
|
|
@@ -237,9 +331,10 @@ def build_contrast_matrix(
|
|
|
237
331
|
Args:
|
|
238
332
|
contrast_type: Type of contrast:
|
|
239
333
|
- "pairwise": All pairwise comparisons (k(k-1)/2 contrasts)
|
|
240
|
-
- "revpairwise": Reversed pairwise comparisons
|
|
241
334
|
- "trt.vs.ctrl" or "treatment": Compare each level to first level
|
|
242
335
|
- "sequential": Successive differences (level[i+1] - level[i])
|
|
336
|
+
- "sum": Each level vs grand mean (deviation coding)
|
|
337
|
+
- "helmert": Each level vs mean of previous levels
|
|
243
338
|
- dict: Custom contrasts with names as keys and weights as values
|
|
244
339
|
levels: List of factor levels.
|
|
245
340
|
normalize: If True, normalize custom contrasts to sum to 1/-1.
|
|
@@ -281,10 +376,6 @@ def build_contrast_matrix(
|
|
|
281
376
|
# All pairwise comparisons: B-A, C-A, C-B, ...
|
|
282
377
|
return build_all_pairwise_contrast(n_levels)
|
|
283
378
|
|
|
284
|
-
elif contrast_type == "revpairwise":
|
|
285
|
-
# Reversed pairwise: A-B, A-C, B-C, ...
|
|
286
|
-
return -build_all_pairwise_contrast(n_levels)
|
|
287
|
-
|
|
288
379
|
elif contrast_type in ("trt.vs.ctrl", "treatment"):
|
|
289
380
|
# Each level vs first level
|
|
290
381
|
return build_pairwise_contrast(n_levels)
|
|
@@ -293,14 +384,23 @@ def build_contrast_matrix(
|
|
|
293
384
|
# Successive differences: B-A, C-B, D-C, ...
|
|
294
385
|
return build_sequential_contrast(n_levels)
|
|
295
386
|
|
|
387
|
+
elif contrast_type == "sum":
|
|
388
|
+
# Each level vs grand mean (deviation coding)
|
|
389
|
+
return build_sum_to_zero_contrast(n_levels)
|
|
390
|
+
|
|
391
|
+
elif contrast_type == "helmert":
|
|
392
|
+
# Each level vs mean of previous levels
|
|
393
|
+
return build_helmert_contrast(n_levels)
|
|
394
|
+
|
|
296
395
|
else:
|
|
297
396
|
raise ValueError(
|
|
298
397
|
f"Unknown contrast type: {contrast_type!r}\n\n"
|
|
299
398
|
"Supported types:\n"
|
|
300
399
|
" - 'pairwise': All pairwise comparisons\n"
|
|
301
|
-
" - 'revpairwise': Reversed pairwise\n"
|
|
302
400
|
" - 'sequential': Successive differences (level[i+1] - level[i])\n"
|
|
303
|
-
" - 'trt.vs.ctrl': Each level vs first level\n"
|
|
401
|
+
" - 'trt.vs.ctrl' / 'treatment': Each level vs first level\n"
|
|
402
|
+
" - 'sum': Each level vs grand mean\n"
|
|
403
|
+
" - 'helmert': Each level vs mean of previous levels\n"
|
|
304
404
|
" - dict: Custom contrasts {name: weights}"
|
|
305
405
|
)
|
|
306
406
|
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/maths/inference/multiplicity.py
RENAMED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
Provides critical value computation for multiplicity-adjusted CIs,
|
|
4
4
|
matching R's emmeans defaults:
|
|
5
5
|
|
|
6
|
-
- Tukey HSD for pairwise
|
|
7
|
-
- Multivariate-t (MVT) for sequential
|
|
6
|
+
- Tukey HSD for pairwise contrasts (studentized range).
|
|
7
|
+
- Multivariate-t (MVT) for sequential, treatment, sum, helmert contrasts
|
|
8
|
+
(Genz-Bretz CDF + root-finding).
|
|
8
9
|
- No adjustment for polynomial contrasts.
|
|
9
10
|
|
|
10
11
|
Internal exports:
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Significant-figures rounding for display output.
|
|
2
|
+
|
|
3
|
+
Provides vectorized rounding to N significant figures, matching R's
|
|
4
|
+
``signif()`` behavior. Used at the user-facing API boundary to produce
|
|
5
|
+
clean DataFrame output without altering internal computation precision.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import polars as pl
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"round_float_columns",
|
|
15
|
+
"round_sigfigs",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def round_sigfigs(x: np.ndarray, n: int = 4) -> np.ndarray:
|
|
20
|
+
"""Round array values to *n* significant figures.
|
|
21
|
+
|
|
22
|
+
Matches R's ``signif()`` behavior: the *n* most significant digits
|
|
23
|
+
are preserved regardless of magnitude.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
x: Input array (float64). May contain NaN or inf values.
|
|
27
|
+
n: Number of significant figures. Must be >= 1.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Array of the same shape with values rounded to *n* significant
|
|
31
|
+
figures. NaN and inf values are passed through unchanged.
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
>>> round_sigfigs(np.array([0.00012345, 3.14159, 12345.68]), n=4)
|
|
35
|
+
array([1.235e-04, 3.142e+00, 1.235e+04])
|
|
36
|
+
"""
|
|
37
|
+
x = np.asarray(x, dtype=np.float64)
|
|
38
|
+
result = x.copy()
|
|
39
|
+
|
|
40
|
+
# Only round finite, non-zero values
|
|
41
|
+
mask = np.isfinite(x) & (x != 0)
|
|
42
|
+
if not mask.any():
|
|
43
|
+
return result
|
|
44
|
+
|
|
45
|
+
vals = x[mask]
|
|
46
|
+
magnitude = np.floor(np.log10(np.abs(vals)))
|
|
47
|
+
shift = 10.0 ** (magnitude - n + 1)
|
|
48
|
+
result[mask] = np.round(vals / shift) * shift
|
|
49
|
+
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def round_float_columns(df: pl.DataFrame, digits: int = 4) -> pl.DataFrame:
|
|
54
|
+
"""Round all Float64 columns to *digits* significant figures.
|
|
55
|
+
|
|
56
|
+
Non-float columns (String, Int32, Int64, etc.) are passed through
|
|
57
|
+
unchanged. Null values within float columns are preserved.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
df: Input DataFrame.
|
|
61
|
+
digits: Number of significant figures. Must be >= 1.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
New DataFrame with Float64 columns rounded.
|
|
65
|
+
"""
|
|
66
|
+
float_cols = [c for c in df.columns if df[c].dtype == pl.Float64]
|
|
67
|
+
if not float_cols:
|
|
68
|
+
return df
|
|
69
|
+
|
|
70
|
+
replacements = []
|
|
71
|
+
for col_name in float_cols:
|
|
72
|
+
series = df[col_name]
|
|
73
|
+
if series.null_count() == len(series):
|
|
74
|
+
# All nulls — nothing to round
|
|
75
|
+
replacements.append(series)
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
arr = series.to_numpy(allow_copy=True)
|
|
79
|
+
rounded = round_sigfigs(arr, n=digits)
|
|
80
|
+
|
|
81
|
+
# Preserve nulls from the original series
|
|
82
|
+
new_series = pl.Series(col_name, rounded)
|
|
83
|
+
if series.null_count() > 0:
|
|
84
|
+
null_mask = series.is_null()
|
|
85
|
+
new_series = new_series.set(null_mask, None)
|
|
86
|
+
|
|
87
|
+
replacements.append(new_series)
|
|
88
|
+
|
|
89
|
+
return df.with_columns(replacements)
|
{bossanova-0.1.0.dev14 → bossanova-0.1.0.dev15}/bossanova/internal/operations/common/__init__.py
RENAMED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
"""Common utilities shared across operations modules."""
|
|
2
2
|
|
|
3
|
+
from bossanova.internal.operations.common.contrast_registry import (
|
|
4
|
+
CONTRAST_ALIASES,
|
|
5
|
+
DEGREE_FUNCTIONS,
|
|
6
|
+
ORDER_DEPENDENT,
|
|
7
|
+
REF_FUNCTIONS,
|
|
8
|
+
VALID_CONTRAST_FUNCTIONS,
|
|
9
|
+
resolve_contrast_name,
|
|
10
|
+
)
|
|
3
11
|
from bossanova.internal.operations.common.data_utils import filter_valid_rows
|
|
4
12
|
from bossanova.internal.operations.common.factors import (
|
|
5
13
|
get_factor_levels,
|
|
@@ -11,9 +19,15 @@ from bossanova.internal.operations.common.formula_utils import (
|
|
|
11
19
|
)
|
|
12
20
|
|
|
13
21
|
__all__ = [
|
|
22
|
+
"CONTRAST_ALIASES",
|
|
23
|
+
"DEGREE_FUNCTIONS",
|
|
24
|
+
"ORDER_DEPENDENT",
|
|
25
|
+
"REF_FUNCTIONS",
|
|
26
|
+
"VALID_CONTRAST_FUNCTIONS",
|
|
14
27
|
"build_ablated_formula",
|
|
15
28
|
"filter_valid_rows",
|
|
16
29
|
"get_factor_levels",
|
|
17
30
|
"infer_factor_levels_from_data",
|
|
18
31
|
"remove_predictor_from_formula",
|
|
32
|
+
"resolve_contrast_name",
|
|
19
33
|
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Contrast function registry for explore formulas.
|
|
2
|
+
|
|
3
|
+
Centralizes the vocabulary of contrast function names, aliases,
|
|
4
|
+
and parameter requirements. Used by the explore parser and contrast
|
|
5
|
+
dispatch logic to ensure consistent naming.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"CONTRAST_ALIASES",
|
|
12
|
+
"DEGREE_FUNCTIONS",
|
|
13
|
+
"ORDER_DEPENDENT",
|
|
14
|
+
"REF_FUNCTIONS",
|
|
15
|
+
"VALID_CONTRAST_FUNCTIONS",
|
|
16
|
+
"resolve_contrast_name",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Canonical names and their aliases.
|
|
20
|
+
# Keys = alias, Values = canonical name.
|
|
21
|
+
CONTRAST_ALIASES: dict[str, str] = {
|
|
22
|
+
"pairwise": "pairwise",
|
|
23
|
+
"sequential": "sequential",
|
|
24
|
+
"poly": "poly",
|
|
25
|
+
"treatment": "treatment",
|
|
26
|
+
"dummy": "treatment",
|
|
27
|
+
"sum": "sum",
|
|
28
|
+
"deviation": "sum",
|
|
29
|
+
"helmert": "helmert",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# All valid contrast function names (canonical + aliases)
|
|
33
|
+
VALID_CONTRAST_FUNCTIONS: frozenset[str] = frozenset(CONTRAST_ALIASES.keys())
|
|
34
|
+
|
|
35
|
+
# Functions that accept a ``degree`` parameter
|
|
36
|
+
DEGREE_FUNCTIONS: frozenset[str] = frozenset({"poly"})
|
|
37
|
+
|
|
38
|
+
# Functions that require a ``ref`` parameter
|
|
39
|
+
REF_FUNCTIONS: frozenset[str] = frozenset({"treatment", "dummy"})
|
|
40
|
+
|
|
41
|
+
# Order-dependent functions (level ordering matters)
|
|
42
|
+
ORDER_DEPENDENT: frozenset[str] = frozenset({"sequential", "poly", "helmert"})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def resolve_contrast_name(name: str) -> str:
|
|
46
|
+
"""Resolve a contrast function name to its canonical form.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
name: Contrast function name (may be an alias).
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Canonical contrast name.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ValueError: If name is not a recognized contrast function.
|
|
56
|
+
"""
|
|
57
|
+
canonical = CONTRAST_ALIASES.get(name)
|
|
58
|
+
if canonical is None:
|
|
59
|
+
valid = ", ".join(sorted(VALID_CONTRAST_FUNCTIONS))
|
|
60
|
+
raise ValueError(f"Unknown contrast function '{name}'. Valid options: {valid}")
|
|
61
|
+
return canonical
|