bossanova 0.1.0.dev25__tar.gz → 0.1.0.dev27__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.dev25 → bossanova-0.1.0.dev27}/PKG-INFO +1 -1
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/dataframes.py +124 -18
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/state.py +4 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/schemas.py +10 -1
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/inference.py +3 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/diagnostics.py +18 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/varying.py +113 -6
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/cv.py +6 -2
- bossanova-0.1.0.dev27/bossanova/internal/infer/profile.py +215 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/compute.py +29 -9
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/__init__.py +8 -8
- bossanova-0.1.0.dev27/bossanova/internal/maths/inference/profile.py +685 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/initialization.py +2 -2
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/model/core.py +15 -9
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/model/summary.py +14 -13
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/pyproject.toml +1 -1
- bossanova-0.1.0.dev25/bossanova/internal/infer/profile.py +0 -194
- bossanova-0.1.0.dev25/bossanova/internal/maths/inference/profile.py +0 -626
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/.gitignore +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/LICENSE +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/README.md +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/README.md +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/advertising.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/cake.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/chickweight.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/credit.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/gammas.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/mtcars.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/penguins.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/poker.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/sleep.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/titanic.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/titanic_test.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/data/titanic_train.csv +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/distributions/continuous.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/distributions/discrete.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/distributions/varying.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/expressions.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/compare.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/cv.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/deviance.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/f_test.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/helpers.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/ic.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/lrt.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/lrt_compare.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/compare/refit.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/resamples.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/results.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/specs.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/data.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/display.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/explore.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/fit.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/formula.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/marginal.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/mixed.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/prediction.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/simulation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/specs.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/validators.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/design/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/design/coding.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/design/names.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/design/reference.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/design/z_matrix.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/convergence.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/dispatch.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/glm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/glmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/grid.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/lifecycle.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/lmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/ols.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/fit/predict.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/bundle.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/contrast_registry.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/contrast_specs.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/design.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/encoding.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/evaluate.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/evaluate_contrast.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/evaluate_newdata.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/evaluate_transforms.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/helpers.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parse.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parser/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parser/expr.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parser/parser.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parser/scanner.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/parser/token.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/formula/random_effects.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/asymptotic.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/bootstrap.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/dispatch.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/formula_utils.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/mee.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/params.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/permutation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/prediction.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/common.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/core.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/glm_operators.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/glmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/lm_operators.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/lmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/results.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample/simulate.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/resample_bundle.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/satterthwaite_emm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/infer/simulation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/bracket_contrasts.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/conditions.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/contrasts.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/emm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/explore.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/explore_parser.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/explore_scanner.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/factors.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/grid.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/inference.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/joint_tests.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/matrices.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/resolve.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/slopes.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/transforms.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/marginal/validation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/backend/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/backend/dispatch.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/backend/jax.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/backend/numpy.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/backend/protocol.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/batching.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/config.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/convergence.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/differentiation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/algebra.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/base.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/core.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/derived.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/factories.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/plotting.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/distributions/probability.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/binomial.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/create.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/gamma.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/gaussian.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/links.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/poisson.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/response.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/schema.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/family/tdist.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/diagnostics.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/estimation.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/hypothesis.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/information_criteria.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/multiplicity.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/sandwich.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/satterthwaite.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/wald_variance.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/inference/welch.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/qr.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/rank.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/schur.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/sparse.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/linalg/svd.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/predict.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/rng.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/rounding.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/glm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/glmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/heuristics.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/lambda_builder.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/lambda_sparse.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/lambda_template.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/lmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/optimize.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/pirls_sparse.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/solvers/quadrature.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/tolerances.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/transforms.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/variance.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/maths/weights.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/rendering/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/rendering/latex.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/rendering/markdown.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/generate.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/glm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/glmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/lm.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/dgp/lmer.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/harness.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/lifecycle.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/metrics.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/model_sim.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/simulation/power.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/README.md +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/compare.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/core.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/core_data.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/core_protocols.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/core_sizing.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/core_viz.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/design.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/helpers.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/mem.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/mem_forest.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/params.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/predict.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/profile.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/ranef.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/relationships.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/resamples.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/resid.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/viz/vif.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/model/__init__.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/model/guards.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/model/result.py +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/py.typed +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/tests/bossanova_benchmarks/bootstrap/data/README.md +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/tests/bossanova_benchmarks/insteval/data/README.md +0 -0
- {bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/tests/bossanova_tests/hypothesis/README.md +0 -0
{bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/dataframes.py
RENAMED
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
from typing import TYPE_CHECKING
|
|
12
12
|
|
|
13
|
+
import numpy as np
|
|
13
14
|
import polars as pl
|
|
14
15
|
|
|
15
16
|
from bossanova.internal.containers.builders.results import (
|
|
@@ -183,35 +184,140 @@ def build_varying_params_dataframe(
|
|
|
183
184
|
def build_varying_spread_dataframe(
|
|
184
185
|
varying_spread: VaryingSpreadState,
|
|
185
186
|
) -> pl.DataFrame:
|
|
186
|
-
"""Build
|
|
187
|
+
"""Build long-form ``.varying_spread`` DataFrame from variance components.
|
|
188
|
+
|
|
189
|
+
Produces a tidy DataFrame with one row per (term, statistic) pair.
|
|
190
|
+
Variance terms (sigma2, tau2) get both ``variance`` and ``std_dev``
|
|
191
|
+
rows. Correlations get a ``corr`` row. ICC gets an ``icc`` row.
|
|
187
192
|
|
|
188
193
|
Args:
|
|
189
194
|
varying_spread: Variance component state with components DataFrame
|
|
190
195
|
and optional CI information.
|
|
191
196
|
|
|
192
197
|
Returns:
|
|
193
|
-
DataFrame with ``
|
|
194
|
-
``ci_lower``, ``ci_upper``, ``ci_method
|
|
198
|
+
DataFrame with columns ``term``, ``statistic``, ``estimate``,
|
|
199
|
+
and optional ``ci_lower``, ``ci_upper``, ``ci_method``.
|
|
195
200
|
"""
|
|
196
|
-
|
|
201
|
+
has_ci = varying_spread.has_inference
|
|
202
|
+
terms: list[str] = []
|
|
203
|
+
statistics: list[str] = []
|
|
204
|
+
estimates: list[float] = []
|
|
205
|
+
ci_lowers: list[float] = []
|
|
206
|
+
ci_uppers: list[float] = []
|
|
207
|
+
ci_methods: list[str] = []
|
|
208
|
+
|
|
209
|
+
# Process components with sigma2 deferred to the end so Residual rows
|
|
210
|
+
# appear last, after all random effect terms.
|
|
211
|
+
comp_names = varying_spread.components[Col.COMPONENT].to_list()
|
|
212
|
+
deferred_sigma2: float | None = None
|
|
213
|
+
|
|
214
|
+
for comp_name in comp_names:
|
|
215
|
+
estimate = varying_spread.components.filter(pl.col(Col.COMPONENT) == comp_name)[
|
|
216
|
+
Col.ESTIMATE
|
|
217
|
+
].item()
|
|
218
|
+
|
|
219
|
+
if comp_name == Col.SIGMA2:
|
|
220
|
+
deferred_sigma2 = estimate
|
|
221
|
+
elif comp_name.startswith(Col.TAU2_PREFIX):
|
|
222
|
+
# "tau2_Subject:Intercept" → "Subject | Intercept"
|
|
223
|
+
term = comp_name[len(Col.TAU2_PREFIX) :].replace(":", " | ")
|
|
224
|
+
_add_variance_rows(
|
|
225
|
+
term,
|
|
226
|
+
estimate,
|
|
227
|
+
comp_name,
|
|
228
|
+
varying_spread,
|
|
229
|
+
has_ci,
|
|
230
|
+
terms,
|
|
231
|
+
statistics,
|
|
232
|
+
estimates,
|
|
233
|
+
ci_lowers,
|
|
234
|
+
ci_uppers,
|
|
235
|
+
ci_methods,
|
|
236
|
+
)
|
|
237
|
+
elif comp_name.startswith(Col.RHO_PREFIX):
|
|
238
|
+
# "rho_Intercept:Days" → "Intercept:Days"
|
|
239
|
+
term = comp_name[len(Col.RHO_PREFIX) :]
|
|
240
|
+
terms.append(term)
|
|
241
|
+
statistics.append("corr")
|
|
242
|
+
estimates.append(estimate)
|
|
243
|
+
if has_ci:
|
|
244
|
+
ci_lowers.append(varying_spread.ci_lower.get(comp_name, float("nan")))
|
|
245
|
+
ci_uppers.append(varying_spread.ci_upper.get(comp_name, float("nan")))
|
|
246
|
+
ci_methods.append(varying_spread.ci_method or "")
|
|
247
|
+
elif comp_name == Col.ICC:
|
|
248
|
+
terms.append("ICC")
|
|
249
|
+
statistics.append("icc")
|
|
250
|
+
estimates.append(estimate)
|
|
251
|
+
if has_ci:
|
|
252
|
+
ci_lowers.append(varying_spread.ci_lower.get(comp_name, float("nan")))
|
|
253
|
+
ci_uppers.append(varying_spread.ci_upper.get(comp_name, float("nan")))
|
|
254
|
+
ci_methods.append(varying_spread.ci_method or "")
|
|
255
|
+
|
|
256
|
+
# Append Residual rows last
|
|
257
|
+
if deferred_sigma2 is not None:
|
|
258
|
+
_add_variance_rows(
|
|
259
|
+
"Residual",
|
|
260
|
+
deferred_sigma2,
|
|
261
|
+
Col.SIGMA2,
|
|
262
|
+
varying_spread,
|
|
263
|
+
has_ci,
|
|
264
|
+
terms,
|
|
265
|
+
statistics,
|
|
266
|
+
estimates,
|
|
267
|
+
ci_lowers,
|
|
268
|
+
ci_uppers,
|
|
269
|
+
ci_methods,
|
|
270
|
+
)
|
|
197
271
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
272
|
+
data: dict[str, list] = {
|
|
273
|
+
Col.TERM: terms,
|
|
274
|
+
Col.METRIC: statistics,
|
|
275
|
+
Col.ESTIMATE: estimates,
|
|
276
|
+
}
|
|
277
|
+
if has_ci:
|
|
278
|
+
data[Col.CI_LOWER] = ci_lowers
|
|
279
|
+
data[Col.CI_UPPER] = ci_uppers
|
|
280
|
+
data[Col.CI_METHOD] = ci_methods
|
|
202
281
|
|
|
203
|
-
|
|
204
|
-
ci_lower_vals.append(varying_spread.ci_lower.get(comp_name, float("nan")))
|
|
205
|
-
ci_upper_vals.append(varying_spread.ci_upper.get(comp_name, float("nan")))
|
|
206
|
-
ci_method_vals.append(varying_spread.ci_method or "")
|
|
282
|
+
return pl.DataFrame(data)
|
|
207
283
|
|
|
208
|
-
result = result.with_columns(
|
|
209
|
-
pl.Series(Col.CI_LOWER, ci_lower_vals),
|
|
210
|
-
pl.Series(Col.CI_UPPER, ci_upper_vals),
|
|
211
|
-
pl.Series(Col.CI_METHOD, ci_method_vals),
|
|
212
|
-
)
|
|
213
284
|
|
|
214
|
-
|
|
285
|
+
def _add_variance_rows(
|
|
286
|
+
term: str,
|
|
287
|
+
variance: float,
|
|
288
|
+
comp_name: str,
|
|
289
|
+
varying_spread: VaryingSpreadState,
|
|
290
|
+
has_ci: bool,
|
|
291
|
+
terms: list[str],
|
|
292
|
+
statistics: list[str],
|
|
293
|
+
estimates: list[float],
|
|
294
|
+
ci_lowers: list[float],
|
|
295
|
+
ci_uppers: list[float],
|
|
296
|
+
ci_methods: list[str],
|
|
297
|
+
) -> None:
|
|
298
|
+
"""Append variance and std_dev rows for a single term."""
|
|
299
|
+
sd = np.sqrt(variance) if variance >= 0 else 0.0
|
|
300
|
+
|
|
301
|
+
# Variance row
|
|
302
|
+
terms.append(term)
|
|
303
|
+
statistics.append("variance")
|
|
304
|
+
estimates.append(variance)
|
|
305
|
+
if has_ci:
|
|
306
|
+
ci_lowers.append(varying_spread.ci_lower.get(comp_name, float("nan")))
|
|
307
|
+
ci_uppers.append(varying_spread.ci_upper.get(comp_name, float("nan")))
|
|
308
|
+
ci_methods.append(varying_spread.ci_method or "")
|
|
309
|
+
|
|
310
|
+
# Std dev row
|
|
311
|
+
terms.append(term)
|
|
312
|
+
statistics.append("std_dev")
|
|
313
|
+
estimates.append(sd)
|
|
314
|
+
if has_ci:
|
|
315
|
+
# Convert variance CIs to SD CIs
|
|
316
|
+
var_lo = varying_spread.ci_lower.get(comp_name, float("nan"))
|
|
317
|
+
var_hi = varying_spread.ci_upper.get(comp_name, float("nan"))
|
|
318
|
+
ci_lowers.append(np.sqrt(var_lo) if var_lo >= 0 else float("nan"))
|
|
319
|
+
ci_uppers.append(np.sqrt(var_hi) if var_hi >= 0 else float("nan"))
|
|
320
|
+
ci_methods.append(varying_spread.ci_method or "")
|
|
215
321
|
|
|
216
322
|
|
|
217
323
|
def build_varying_corr_dataframe(
|
{bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/builders/state.py
RENAMED
|
@@ -452,6 +452,7 @@ def build_prediction_state(
|
|
|
452
452
|
|
|
453
453
|
def build_cv_state(
|
|
454
454
|
k: int,
|
|
455
|
+
mse: float,
|
|
455
456
|
rmse: float,
|
|
456
457
|
mae: float,
|
|
457
458
|
r_squared: float,
|
|
@@ -471,6 +472,7 @@ def build_cv_state(
|
|
|
471
472
|
|
|
472
473
|
Args:
|
|
473
474
|
k: Number of folds used.
|
|
475
|
+
mse: Mean squared error (out-of-sample).
|
|
474
476
|
rmse: Root mean squared error.
|
|
475
477
|
mae: Mean absolute error.
|
|
476
478
|
r_squared: Coefficient of determination.
|
|
@@ -491,6 +493,7 @@ def build_cv_state(
|
|
|
491
493
|
Examples:
|
|
492
494
|
>>> state = build_cv_state(
|
|
493
495
|
... k=10,
|
|
496
|
+
... mse=0.274,
|
|
494
497
|
... rmse=0.523,
|
|
495
498
|
... mae=0.412,
|
|
496
499
|
... r_squared=0.891,
|
|
@@ -498,6 +501,7 @@ def build_cv_state(
|
|
|
498
501
|
"""
|
|
499
502
|
return CVState(
|
|
500
503
|
k=k,
|
|
504
|
+
mse=mse,
|
|
501
505
|
rmse=rmse,
|
|
502
506
|
mae=mae,
|
|
503
507
|
r_squared=r_squared,
|
|
@@ -98,6 +98,7 @@ class Col:
|
|
|
98
98
|
NULL_DEVIANCE: str = "null_deviance"
|
|
99
99
|
DEVIANCE: str = "deviance"
|
|
100
100
|
DISPERSION: str = "dispersion"
|
|
101
|
+
MSE: str = "mse"
|
|
101
102
|
PSEUDO_RSQUARED: str = "pseudo_rsquared"
|
|
102
103
|
RSQUARED_MARGINAL: str = "rsquared_marginal"
|
|
103
104
|
RSQUARED_CONDITIONAL: str = "rsquared_conditional"
|
|
@@ -112,6 +113,7 @@ class Col:
|
|
|
112
113
|
|
|
113
114
|
# -- Varying (random effects) --
|
|
114
115
|
COMPONENT: str = "component"
|
|
116
|
+
METRIC: str = "metric"
|
|
115
117
|
GROUP: str = "group"
|
|
116
118
|
LEVEL: str = "level"
|
|
117
119
|
EFFECT1: str = "effect1"
|
|
@@ -177,6 +179,8 @@ class Col:
|
|
|
177
179
|
N: str = "n"
|
|
178
180
|
|
|
179
181
|
# -- CV diagnostics --
|
|
182
|
+
CV_MSE: str = "cv_mse"
|
|
183
|
+
CV_MSE_SD: str = "cv_mse_sd"
|
|
180
184
|
CV_RMSE: str = "cv_rmse"
|
|
181
185
|
CV_MAE: str = "cv_mae"
|
|
182
186
|
CV_RSQUARED: str = "cv_rsquared"
|
|
@@ -408,6 +412,7 @@ DiagnosticsGaussian = Schema(
|
|
|
408
412
|
Col.NULL_DEVIANCE: Float64,
|
|
409
413
|
Col.DEVIANCE: Float64,
|
|
410
414
|
Col.DISPERSION: Float64,
|
|
415
|
+
Col.MSE: Float64,
|
|
411
416
|
Col.PSEUDO_RSQUARED: Float64,
|
|
412
417
|
Col.AIC: Float64,
|
|
413
418
|
Col.BIC: Float64,
|
|
@@ -423,6 +428,7 @@ DiagnosticsGlm = Schema(
|
|
|
423
428
|
Col.NULL_DEVIANCE: Float64,
|
|
424
429
|
Col.DEVIANCE: Float64,
|
|
425
430
|
Col.DISPERSION: Float64,
|
|
431
|
+
Col.MSE: Float64,
|
|
426
432
|
Col.PSEUDO_RSQUARED: Float64,
|
|
427
433
|
Col.AIC: Float64,
|
|
428
434
|
Col.BIC: Float64,
|
|
@@ -437,6 +443,7 @@ DiagnosticsLmer = Schema(
|
|
|
437
443
|
Col.DF_RESID: Float64,
|
|
438
444
|
Col.SIGMA: Float64,
|
|
439
445
|
Col.DEVIANCE: Float64,
|
|
446
|
+
Col.MSE: Float64,
|
|
440
447
|
Col.RSQUARED_MARGINAL: Float64,
|
|
441
448
|
Col.RSQUARED_CONDITIONAL: Float64,
|
|
442
449
|
Col.ICC: Float64,
|
|
@@ -447,10 +454,12 @@ DiagnosticsLmer = Schema(
|
|
|
447
454
|
)
|
|
448
455
|
|
|
449
456
|
# CV-augmented columns (added by .infer(how='cv') after .fit())
|
|
450
|
-
DiagnosticsCvCols = (Col.CV_RMSE, Col.CV_MAE, Col.CV_RSQUARED, Col.CV_K)
|
|
457
|
+
DiagnosticsCvCols = (Col.CV_MSE, Col.CV_RMSE, Col.CV_MAE, Col.CV_RSQUARED, Col.CV_K)
|
|
451
458
|
|
|
452
459
|
# Prediction CV columns (added by .predict().infer(how='cv'))
|
|
453
460
|
DiagnosticsPredCvCols = (
|
|
461
|
+
Col.CV_MSE,
|
|
462
|
+
Col.CV_MSE_SD,
|
|
454
463
|
Col.CV_RMSE,
|
|
455
464
|
Col.CV_RMSE_SD,
|
|
456
465
|
Col.CV_MAE,
|
{bossanova-0.1.0.dev25 → bossanova-0.1.0.dev27}/bossanova/internal/containers/structs/inference.py
RENAMED
|
@@ -98,6 +98,9 @@ class CVState:
|
|
|
98
98
|
"""
|
|
99
99
|
|
|
100
100
|
k: int = field(validator=[validators.instance_of(int), validators.gt(0)])
|
|
101
|
+
mse: float = field(
|
|
102
|
+
validator=[validators.instance_of((int, float)), validators.ge(0)]
|
|
103
|
+
)
|
|
101
104
|
rmse: float = field(
|
|
102
105
|
validator=[validators.instance_of((int, float)), validators.ge(0)]
|
|
103
106
|
)
|
|
@@ -267,6 +267,8 @@ def _lm_diagnostics(
|
|
|
267
267
|
fit.null_deviance if fit.null_deviance is not None else float(np.sum(y**2))
|
|
268
268
|
)
|
|
269
269
|
|
|
270
|
+
mse = ss_res / n
|
|
271
|
+
|
|
270
272
|
return {
|
|
271
273
|
Col.RSQUARED: [rsquared],
|
|
272
274
|
Col.RSQUARED_ADJ: [rsquared_adj],
|
|
@@ -276,6 +278,7 @@ def _lm_diagnostics(
|
|
|
276
278
|
Col.NULL_DEVIANCE: [null_deviance],
|
|
277
279
|
Col.DEVIANCE: [deviance],
|
|
278
280
|
Col.DISPERSION: [sigma**2],
|
|
281
|
+
Col.MSE: [mse],
|
|
279
282
|
Col.PSEUDO_RSQUARED: [
|
|
280
283
|
1.0 - deviance / null_deviance if null_deviance > 0 else float("nan")
|
|
281
284
|
],
|
|
@@ -313,10 +316,17 @@ def _glm_diagnostics(
|
|
|
313
316
|
else float("nan")
|
|
314
317
|
)
|
|
315
318
|
|
|
319
|
+
import numpy as np
|
|
320
|
+
|
|
321
|
+
mse = (
|
|
322
|
+
float(np.mean(fit.residuals**2)) if fit.residuals is not None else float("nan")
|
|
323
|
+
)
|
|
324
|
+
|
|
316
325
|
return {
|
|
317
326
|
Col.NULL_DEVIANCE: [null_deviance],
|
|
318
327
|
Col.DEVIANCE: [deviance],
|
|
319
328
|
Col.DISPERSION: [dispersion],
|
|
329
|
+
Col.MSE: [mse],
|
|
320
330
|
Col.PSEUDO_RSQUARED: [pseudo_rsquared],
|
|
321
331
|
}
|
|
322
332
|
|
|
@@ -385,9 +395,14 @@ def _mixed_diagnostics(
|
|
|
385
395
|
var_group_resid = var_random + var_resid
|
|
386
396
|
icc = var_random / var_group_resid if var_group_resid > 0 else 0.0
|
|
387
397
|
|
|
398
|
+
mse = (
|
|
399
|
+
float(np.mean(fit.residuals**2)) if fit.residuals is not None else float("nan")
|
|
400
|
+
)
|
|
401
|
+
|
|
388
402
|
return {
|
|
389
403
|
Col.SIGMA: [sigma],
|
|
390
404
|
Col.DEVIANCE: [deviance],
|
|
405
|
+
Col.MSE: [mse],
|
|
391
406
|
Col.RSQUARED_MARGINAL: [rsquared_marginal],
|
|
392
407
|
Col.RSQUARED_CONDITIONAL: [rsquared_conditional],
|
|
393
408
|
Col.ICC: [icc],
|
|
@@ -403,12 +418,15 @@ def _add_cv_metrics(data: dict[str, list], cv: CVState) -> None:
|
|
|
403
418
|
"""
|
|
404
419
|
import numpy as np
|
|
405
420
|
|
|
421
|
+
data[Col.CV_MSE] = [cv.mse]
|
|
406
422
|
data[Col.CV_RMSE] = [cv.rmse]
|
|
407
423
|
data[Col.CV_MAE] = [cv.mae]
|
|
408
424
|
data[Col.CV_RSQUARED] = [cv.r_squared]
|
|
409
425
|
data[Col.CV_K] = [cv.k]
|
|
410
426
|
|
|
411
427
|
if cv.fold_metrics:
|
|
428
|
+
if "mse" in cv.fold_metrics:
|
|
429
|
+
data[Col.CV_MSE_SD] = [float(np.std(cv.fold_metrics["mse"]))]
|
|
412
430
|
if "rmse" in cv.fold_metrics:
|
|
413
431
|
data[Col.CV_RMSE_SD] = [float(np.std(cv.fold_metrics["rmse"]))]
|
|
414
432
|
if "mae" in cv.fold_metrics:
|
|
@@ -253,10 +253,112 @@ def compute_varying_state(
|
|
|
253
253
|
)
|
|
254
254
|
|
|
255
255
|
|
|
256
|
+
def _get_predictor_column(
|
|
257
|
+
re_name: str,
|
|
258
|
+
X: NDArray[np.floating] | None,
|
|
259
|
+
X_names: tuple[str, ...] | None,
|
|
260
|
+
) -> NDArray[np.floating] | None:
|
|
261
|
+
"""Look up the data column for a random effect predictor.
|
|
262
|
+
|
|
263
|
+
Returns None for ``"Intercept"`` (caller uses all-ones logic) or when
|
|
264
|
+
the predictor cannot be found in the design matrix.
|
|
265
|
+
"""
|
|
266
|
+
if re_name == "Intercept" or X is None or X_names is None:
|
|
267
|
+
return None
|
|
268
|
+
if re_name in X_names:
|
|
269
|
+
return X[:, X_names.index(re_name)]
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _compute_johnson_icc(
|
|
274
|
+
tau2: dict[str, float],
|
|
275
|
+
rho: dict[str, float],
|
|
276
|
+
sigma2: float,
|
|
277
|
+
re_meta: REInfo,
|
|
278
|
+
X: NDArray[np.floating] | None,
|
|
279
|
+
X_names: tuple[str, ...] | None,
|
|
280
|
+
) -> float | None:
|
|
281
|
+
"""Compute ICC using Johnson (2014, PLoS ONE, eq. 10).
|
|
282
|
+
|
|
283
|
+
For each grouping factor, computes the mean random effect variance
|
|
284
|
+
accounting for predictor distributions when random slopes are present:
|
|
285
|
+
|
|
286
|
+
contribution_g = Σ_i Σ_j Cov(b_i, b_j) · E[X_i · X_j]
|
|
287
|
+
|
|
288
|
+
For intercept-only factors this simplifies to τ00. For slope models
|
|
289
|
+
it incorporates E[X] and E[X²] from the data.
|
|
290
|
+
|
|
291
|
+
Falls back to sum(τ00) / (sum(τ00) + σ²) when data is unavailable.
|
|
292
|
+
"""
|
|
293
|
+
group_names = list(re_meta.grouping_vars)
|
|
294
|
+
if not group_names:
|
|
295
|
+
return None
|
|
296
|
+
|
|
297
|
+
# Get per-factor RE names
|
|
298
|
+
re_structures_list = re_meta.metadata.get("re_structures_list", None)
|
|
299
|
+
if re_structures_list is not None and len(re_structures_list) == len(group_names):
|
|
300
|
+
_, names_per_group = per_factor_re_info(re_meta, group_names)
|
|
301
|
+
else:
|
|
302
|
+
# Single-factor model: all random names belong to the one group
|
|
303
|
+
names_per_group = {group_names[0]: re_meta.random_names or ["Intercept"]}
|
|
304
|
+
|
|
305
|
+
var_random = 0.0
|
|
306
|
+
|
|
307
|
+
for group_name in group_names:
|
|
308
|
+
factor_names = names_per_group[group_name]
|
|
309
|
+
k = len(factor_names)
|
|
310
|
+
|
|
311
|
+
# Build covariance matrix for this factor
|
|
312
|
+
cov = np.zeros((k, k))
|
|
313
|
+
for i, name_i in enumerate(factor_names):
|
|
314
|
+
key_i = f"{group_name}:{name_i}"
|
|
315
|
+
cov[i, i] = tau2.get(key_i, 0.0)
|
|
316
|
+
|
|
317
|
+
# Fill off-diagonal from rho
|
|
318
|
+
# NOTE: rho keys are "RE1:RE2" without group prefix. When two groups
|
|
319
|
+
# share the same slope predictor names, the last group's rho wins.
|
|
320
|
+
# This is a known limitation of the current rho dict structure.
|
|
321
|
+
if k > 1:
|
|
322
|
+
for i in range(k):
|
|
323
|
+
for j in range(i + 1, k):
|
|
324
|
+
rho_key = f"{factor_names[i]}:{factor_names[j]}"
|
|
325
|
+
if rho_key in rho:
|
|
326
|
+
cov_ij = rho[rho_key] * np.sqrt(cov[i, i] * cov[j, j])
|
|
327
|
+
cov[i, j] = cov_ij
|
|
328
|
+
cov[j, i] = cov_ij
|
|
329
|
+
|
|
330
|
+
# Build E[X_i · X_j] matrix
|
|
331
|
+
e_xx = np.zeros((k, k))
|
|
332
|
+
cols: list[NDArray[np.floating] | None] = [
|
|
333
|
+
_get_predictor_column(name, X, X_names) for name in factor_names
|
|
334
|
+
]
|
|
335
|
+
for i in range(k):
|
|
336
|
+
for j in range(k):
|
|
337
|
+
ci = cols[i]
|
|
338
|
+
cj = cols[j]
|
|
339
|
+
if ci is not None and cj is not None:
|
|
340
|
+
e_xx[i, j] = np.mean(ci * cj)
|
|
341
|
+
elif ci is None and factor_names[i] == "Intercept":
|
|
342
|
+
# Intercept is all 1s: E[1 · X_j]
|
|
343
|
+
e_xx[i, j] = np.mean(cj) if cj is not None else 1.0
|
|
344
|
+
elif cj is None and factor_names[j] == "Intercept":
|
|
345
|
+
# E[X_i · 1]
|
|
346
|
+
e_xx[i, j] = np.mean(ci) if ci is not None else 1.0
|
|
347
|
+
|
|
348
|
+
var_random += float(np.sum(cov * e_xx))
|
|
349
|
+
|
|
350
|
+
if var_random <= 0:
|
|
351
|
+
return None
|
|
352
|
+
return var_random / (var_random + sigma2)
|
|
353
|
+
|
|
354
|
+
|
|
256
355
|
def compute_varying_spread_state(
|
|
257
356
|
theta: NDArray[np.floating],
|
|
258
357
|
sigma: float,
|
|
259
358
|
re_meta: REInfo,
|
|
359
|
+
*,
|
|
360
|
+
X: NDArray[np.floating] | None = None,
|
|
361
|
+
X_names: tuple[str, ...] | None = None,
|
|
260
362
|
) -> VaryingSpreadState:
|
|
261
363
|
"""Compute VaryingSpreadState (variance components) from theta parameters.
|
|
262
364
|
|
|
@@ -264,10 +366,17 @@ def compute_varying_spread_state(
|
|
|
264
366
|
correlations (rho), and intraclass correlation (ICC) from the fitted
|
|
265
367
|
theta vector using the random effects structure.
|
|
266
368
|
|
|
369
|
+
ICC is computed using Johnson (2014, PLoS ONE, eq. 10) which accounts
|
|
370
|
+
for predictor distributions when random slopes are present. When ``X``
|
|
371
|
+
and ``X_names`` are provided, the formula uses E[X] and E[X²] from
|
|
372
|
+
the data; otherwise falls back to summing intercept variances only.
|
|
373
|
+
|
|
267
374
|
Args:
|
|
268
375
|
theta: Variance component parameters from the fitted model.
|
|
269
376
|
sigma: Residual standard deviation from the fitted model.
|
|
270
377
|
re_meta: Random effects metadata (grouping vars, structure, etc.).
|
|
378
|
+
X: Fixed-effects design matrix (n × p), used for ICC computation.
|
|
379
|
+
X_names: Column names for ``X``, used to look up slope predictors.
|
|
271
380
|
|
|
272
381
|
Returns:
|
|
273
382
|
VaryingSpreadState container with components DataFrame and
|
|
@@ -313,12 +422,8 @@ def compute_varying_spread_state(
|
|
|
313
422
|
tau2_key = name.removesuffix("_sd")
|
|
314
423
|
tau2[tau2_key] = value**2
|
|
315
424
|
|
|
316
|
-
# Compute ICC
|
|
317
|
-
|
|
318
|
-
icc: float | None = None
|
|
319
|
-
total_tau2 = sum(tau2.values())
|
|
320
|
-
if total_tau2 > 0:
|
|
321
|
-
icc = total_tau2 / (total_tau2 + sigma2)
|
|
425
|
+
# Compute ICC using Johnson (2014) formula
|
|
426
|
+
icc = _compute_johnson_icc(tau2, rho, sigma2, re_meta, X, X_names)
|
|
322
427
|
|
|
323
428
|
# Build components DataFrame
|
|
324
429
|
components_data: dict[str, list] = {Col.COMPONENT: [], Col.ESTIMATE: []}
|
|
@@ -403,6 +508,8 @@ def build_mixed_post_fit_state(
|
|
|
403
508
|
theta=fit.theta,
|
|
404
509
|
sigma=sigma,
|
|
405
510
|
re_meta=bundle.re_metadata,
|
|
511
|
+
X=bundle.X,
|
|
512
|
+
X_names=bundle.X_names,
|
|
406
513
|
)
|
|
407
514
|
|
|
408
515
|
# Emit convergence warnings if any issues detected
|
|
@@ -485,8 +485,10 @@ def _compute_fold_metrics(
|
|
|
485
485
|
'sensitivity', 'specificity', 'f1', 'auc'.
|
|
486
486
|
"""
|
|
487
487
|
residuals = y_test - y_pred
|
|
488
|
+
mse = float(np.mean(residuals**2))
|
|
488
489
|
metrics: dict[str, float] = {
|
|
489
|
-
"
|
|
490
|
+
"mse": mse,
|
|
491
|
+
"rmse": float(np.sqrt(mse)),
|
|
490
492
|
"mae": float(np.mean(np.abs(residuals))),
|
|
491
493
|
}
|
|
492
494
|
|
|
@@ -644,7 +646,8 @@ def compute_cv_metrics(
|
|
|
644
646
|
resid_valid = oos_residuals[valid_mask]
|
|
645
647
|
|
|
646
648
|
# Overall out-of-sample metrics
|
|
647
|
-
|
|
649
|
+
mse = float(np.mean(resid_valid**2))
|
|
650
|
+
rmse = float(np.sqrt(mse))
|
|
648
651
|
mae = float(np.mean(np.abs(resid_valid)))
|
|
649
652
|
|
|
650
653
|
# R² computed on out-of-sample predictions
|
|
@@ -666,6 +669,7 @@ def compute_cv_metrics(
|
|
|
666
669
|
|
|
667
670
|
return build_cv_state(
|
|
668
671
|
k=k_int,
|
|
672
|
+
mse=mse,
|
|
669
673
|
rmse=rmse,
|
|
670
674
|
mae=mae,
|
|
671
675
|
r_squared=r_squared,
|