pystatistics 2.0.1__tar.gz → 2.2.0__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.
- {pystatistics-2.0.1 → pystatistics-2.2.0}/CHANGELOG.md +277 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/PKG-INFO +171 -1
- {pystatistics-2.0.1 → pystatistics-2.2.0}/README.md +170 -0
- pystatistics-2.2.0/benchmarks/mvnmle_bench.py +194 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pyproject.toml +1 -1
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/__init__.py +1 -1
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/__init__.py +14 -1
- pystatistics-2.2.0/pystatistics/mvnmle/_monotone.py +230 -0
- pystatistics-2.2.0/pystatistics/mvnmle/backends/_em_batched.py +897 -0
- pystatistics-2.2.0/pystatistics/mvnmle/backends/_squarem.py +235 -0
- pystatistics-2.2.0/pystatistics/mvnmle/backends/em.py +517 -0
- pystatistics-2.2.0/pystatistics/mvnmle/mcar_test.py +664 -0
- pystatistics-2.2.0/pystatistics/mvnmle/solvers.py +344 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/test_gpu.py +55 -0
- pystatistics-2.2.0/tests/mvnmle/test_mcar.py +128 -0
- pystatistics-2.2.0/tests/mvnmle/test_mom_mcar.py +169 -0
- pystatistics-2.2.0/tests/mvnmle/test_monotone.py +241 -0
- pystatistics-2.2.0/tests/mvnmle/test_no_silent_fallback.py +96 -0
- pystatistics-2.2.0/tests/mvnmle/test_squarem.py +120 -0
- pystatistics-2.0.1/pystatistics/mvnmle/backends/em.py +0 -330
- pystatistics-2.0.1/pystatistics/mvnmle/mcar_test.py +0 -228
- pystatistics-2.0.1/pystatistics/mvnmle/solvers.py +0 -195
- pystatistics-2.0.1/tests/mvnmle/test_no_silent_fallback.py +0 -55
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.github/workflows/publish.yml +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.github/workflows/trigger-docs-rebuild.yml +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.gitignore +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.release/CHECKLIST.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.release/UNRELEASED.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/.release/release.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/CLAUDE.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/LICENSE +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/DESIGN.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/Forge.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/GPU_BACKEND_NOTES.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/Makefile +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/PYSTATSBIO_CONTEXT.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/ROADMAP.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/_static/custom.css +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/anova.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/conf.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/core.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/descriptive.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/hypothesis.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/index.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/mixed.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/montecarlo.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/mvnmle.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/regression.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/docs/survival.rst +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/GPU_BACKEND_CONVENTION.md +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_contrasts.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_levene.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_posthoc.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_repeated.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/_ss.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/anova/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/capabilities.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/device.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/batched.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/cholesky.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/determinant.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/qr.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/solve.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/linalg/svd.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/optimization/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/optimization/convergence.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/precision.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/timing.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/compute/tolerances.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/datasource.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/exceptions.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/protocols.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/result.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/core/validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/_missing.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/_quantile_types.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/descriptive/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_basis.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_fit.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_gam.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_gcv.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/_smooth.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/backends/_gpu_family.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/backends/gpu_pirls.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/gam/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/_design_factories.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/_p_adjust.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_chisq_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_fisher_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_ks_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_prop_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_t_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_var_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/_wilcox_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/hypothesis/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_deviance.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_pirls.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_pls.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_random_effects.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/_satterthwaite.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mixed/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/_ci.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/_influence.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/montecarlo/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/_likelihood.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/_solver.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/backends/gpu_likelihood.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multinomial/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/_factor.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/_pca.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/_rotation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/multivariate/backends/gpu_pca.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/base.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/gpu_fp32.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/gpu_fp64.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_objectives/parameterizations.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/_utils.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/datasets.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/patterns.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/mvnmle/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/_likelihood.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/_solver.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/backends/gpu_likelihood.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/ordinal/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/py.typed +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/_formatting.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/_glm.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/_linear.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/_nb_theta.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/backends/cpu_glm.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/backends/gpu_glm.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/families.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/regression/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/_cox.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/_discrete.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/_km.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/_logrank.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/backends/cpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/backends/gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/solution.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/survival/solvers.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_acf.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_batch.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_factored.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_fit.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_forecast.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_kalman.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_likelihood.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_arima_order.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_common.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_decomposition.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_differencing.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_ets_fit.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_ets_forecast.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_ets_models.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_stationarity.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/_whittle.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/backends/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/backends/whittle_batch_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/pystatistics/timeseries/backends/whittle_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_contrasts.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_design.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_factorial.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_levene.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_oneway.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_posthoc.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/anova/test_repeated_measures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/benchmark_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/core/test_datasource.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/core/test_exceptions.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/core/test_result.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/core/test_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_cor.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_cov.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_describe.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_missing.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_moments.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_quantile.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/descriptive/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_ancova_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_ancova_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_bonferroni_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_bonferroni_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_eta_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_eta_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_levene_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_levene_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_oneway_balanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_oneway_balanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_oneway_unbalanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_oneway_unbalanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_rm_mixed_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_rm_mixed_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_rm_within_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_rm_within_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_tukey_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_tukey_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_twoway_balanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_twoway_balanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_twoway_unbalanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/anova_twoway_unbalanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/basic_100x3.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/basic_100x3_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/basic_100x3_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/collinear_almost.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/collinear_almost_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/collinear_almost_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_basic_100x5.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_basic_100x5_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_basic_100x5_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_constant_column.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_constant_column_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_constant_column_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_extreme_values.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_extreme_values_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_extreme_values_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_large_1000x10.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_large_1000x10_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_large_1000x10_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_columnwise.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_columnwise_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_columnwise_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_scattered.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_scattered_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_nan_scattered_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_negative_correlation.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_negative_correlation_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_negative_correlation_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_perfect_correlation.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_perfect_correlation_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_perfect_correlation_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_single_column.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_single_column_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_single_column_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_ties.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_ties_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/desc_ties_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/different_scales.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/different_scales_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/different_scales_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_anova_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_descriptive_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_glm_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_hypothesis_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_mixed_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_montecarlo_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/generate_survival_fixtures.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_balanced.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_balanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_balanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_basic.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_basic_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_basic_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_large.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_large_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_large_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_separated.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_separated_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_binomial_separated_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_basic.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_basic_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_basic_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_large.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_large_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_gaussian_large_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_basic.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_basic_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_basic_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_large_counts.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_large_counts_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_large_counts_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_zeros.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_zeros_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/glm_poisson_zeros_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/high_noise.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/high_noise_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/high_noise_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_2x2_yates_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_2x2_yates_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_3x3_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_3x3_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_gof_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_gof_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_gof_unequal_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_chisq_gof_unequal_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_2x2_less_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_2x2_less_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_2x2_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_2x2_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_3x3_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_fisher_3x3_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_ks_onesample_norm_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_ks_onesample_norm_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_ks_twosample_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_ks_twosample_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_prop_onesample_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_prop_onesample_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_prop_twosample_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_prop_twosample_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_onesample_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_onesample_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_paired_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_paired_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_pooled_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_pooled_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_welch_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_t_welch_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_var_basic_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_var_basic_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_wilcox_ranksum_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_wilcox_ranksum_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_wilcox_signed_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/htest_wilcox_signed_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/ill_conditioned.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/ill_conditioned_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/ill_conditioned_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/large_coeffs.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/large_coeffs_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/large_coeffs_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_90_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_90_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_normal_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_normal_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_skewed_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_ci_skewed_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_mean_balanced_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_mean_balanced_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_mean_ordinary_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_mean_ordinary_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_median_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_median_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_variance_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_boot_variance_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_greater_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_greater_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_not_significant_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_not_significant_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_significant_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mc_perm_significant_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/glmm_binomial.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/glmm_poisson.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/lmm_crossed.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/lmm_intercept.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/lmm_ml.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/lmm_no_effect.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/lmm_slope.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/mixed_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/mixed/mixed_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/near_square.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/near_square_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/near_square_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/no_intercept.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/no_intercept_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/no_intercept_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_anova_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_descriptive_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_glm_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_hypothesis_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_mixed_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_montecarlo_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_survival_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_r_validation.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/run_validation.sh +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/small_noise.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/small_noise_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/small_noise_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_breslow_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_breslow_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_single_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_single_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_ties_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_ties_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_two_cov_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_cox_two_cov_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_basic_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_basic_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_heavy_cens_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_heavy_cens_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_loglog_ci_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_loglog_ci_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_no_cens_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_no_cens_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_plain_ci_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_plain_ci_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_ties_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_km_ties_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_peto_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_peto_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_three_group_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_three_group_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_two_group_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/surv_lr_two_group_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/tall_skinny.csv +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/tall_skinny_meta.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/tall_skinny_r_results.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/fixtures/validate_against_r.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/gam/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/gam/test_gam.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_chisq_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_design_split.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_fisher_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_ks_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_p_adjust.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_prop_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_t_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_var_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/hypothesis/test_wilcox_test.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_glmm.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_lmm_crossed.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_lmm_intercept.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_lmm_nested.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_lmm_slope.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_pls.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_random_effects.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mixed/test_satterthwaite.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_batched_solver.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_boot_ci.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_bootstrap.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_influence.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_permutation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/montecarlo/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/multinomial/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/multinomial/test_multinom.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/multivariate/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/multivariate/test_multivariate.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/apple_em_reference.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/apple_reference.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/generate_em_fixtures.R +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_apple.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_complete.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_extreme.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_missvals.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_simple_mcar.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/little_mcar_summary.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/missvals_em_reference.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/missvals_reference.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/references/small_test_reference.json +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/test_em.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/mvnmle/test_mlest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/ordinal/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/ordinal/test_ordinal.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/benchmark.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/benchmark.r +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_fit.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_gamma_nb.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_glm.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_glm_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_glm_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_module_split.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/regression/test_stress_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/conftest.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_coxph.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_discrete_time.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_gpu.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_kaplan_meier.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_logrank.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/survival/test_r_validation.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/test_code_quality.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/timeseries/__init__.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/timeseries/test_acf_stationarity.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/timeseries/test_arima.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/timeseries/test_decomposition.py +0 -0
- {pystatistics-2.0.1 → pystatistics-2.2.0}/tests/timeseries/test_ets.py +0 -0
|
@@ -1,5 +1,282 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
- Fixed a `torch._C._LinAlgError` crash in `chi_square_mcar_batched_torch`
|
|
6
|
+
(`pystatistics/mvnmle/backends/_em_batched.py`) on GPU FP32. The batched
|
|
7
|
+
MoM fast path selected `cholesky_solve` when the SVD-based condition
|
|
8
|
+
number was below threshold, but Cholesky requires positive-definiteness,
|
|
9
|
+
which is strictly stronger than good conditioning. On GPU FP32, real
|
|
10
|
+
tabular data (e.g. `lacuna_tabular_110` applied to UCI/OpenML datasets)
|
|
11
|
+
can produce `sigma_oo` with good cond number but tiny negative eigenvalues
|
|
12
|
+
from roundoff, making Cholesky fail. Fix: wrap the fast path in
|
|
13
|
+
`try/except torch._C._LinAlgError`; on failure, fall back to
|
|
14
|
+
`torch.linalg.pinv` for the batch (honouring the `regularize` flag —
|
|
15
|
+
`regularize=False` still raises). Surfaced by dogfooding via Project
|
|
16
|
+
Lacuna on 3,080 (dataset × generator) pairs across the 110-generator
|
|
17
|
+
tabular registry; previously `mom_mcar_test` crashed on the first batch
|
|
18
|
+
containing breast_cancer / wine / credit_card_default.
|
|
19
|
+
|
|
20
|
+
- Fixed an exception-type leak in `little_mcar_test`
|
|
21
|
+
(`pystatistics/mvnmle/mcar_test.py:~250`). The ML-estimation try/except
|
|
22
|
+
wrapped *every* exception — including `PyStatisticsError` subclasses
|
|
23
|
+
like `NumericalError` — as a bare `RuntimeError`, breaking the
|
|
24
|
+
documented `except PyStatisticsError:` pattern downstream and losing
|
|
25
|
+
the original exception chain. Fix: explicitly re-raise
|
|
26
|
+
`PyStatisticsError`, and use `raise ... from e` for anything else so
|
|
27
|
+
the chain is preserved. Surfaced by Project Lacuna's cache builder,
|
|
28
|
+
which catches `PyStatisticsError` to fall back to a sentinel entry
|
|
29
|
+
when Little's test is numerically unfit for a particular
|
|
30
|
+
(dataset, generator) pair; MLE failures were leaking past the catch
|
|
31
|
+
and killing the whole build.
|
|
32
|
+
|
|
33
|
+
- Added ridge-fallback to the batched Cholesky sites inside the EM
|
|
34
|
+
E-step / log-likelihood
|
|
35
|
+
(`pystatistics/mvnmle/backends/_em_batched.py`):
|
|
36
|
+
`e_step_full_batched_np` (line ~361), `_e_step_full_torch` (~680), and
|
|
37
|
+
`_loglik_full_batched_torch` (~797). These compute per-pattern
|
|
38
|
+
Cholesky of sigma_oo sub-blocks; real tabular data can produce
|
|
39
|
+
individual sub-blocks that are numerically indefinite even when the
|
|
40
|
+
global sigma is PD (integer-encoded categoricals with heavy
|
|
41
|
+
collinearity in the intersection of a given missingness pattern's
|
|
42
|
+
observed variables). Fix: wrap each site in `try/except LinAlgError`
|
|
43
|
+
with a `ridge·I` retry (ridge = 1e-10 at pattern scale; statistically
|
|
44
|
+
invisible). Also removed a dead Cholesky call in `e_step_batched_np`
|
|
45
|
+
whose result was never used — it was only a crash liability.
|
|
46
|
+
`np.linalg.solve` at that same site now has a pinv fallback for
|
|
47
|
+
singular sub-blocks.
|
|
48
|
+
|
|
49
|
+
- Added `regularize: bool = True` to `mlest`, `_solve_em`, and
|
|
50
|
+
`EMBackend.solve`, mirroring the existing convention on
|
|
51
|
+
`mom_mcar_test` / `little_mcar_test`. When True (new default),
|
|
52
|
+
`EMBackend._ensure_pd` applies a small diagonal ridge
|
|
53
|
+
(`max(0, 1e-10 - min_eig) + 1e-12`) to the M-step sigma whenever its
|
|
54
|
+
smallest eigenvalue falls below the PD threshold, rather than raising
|
|
55
|
+
`NumericalError` outright. The ridge is vanishingly small relative to
|
|
56
|
+
any real data scale — the typical case the old path rejected had
|
|
57
|
+
min_eig ≈ 1e-13 from pure FP64 roundoff — and a UserWarning makes the
|
|
58
|
+
event visible in logs. Call sites that need strict bit-for-bit
|
|
59
|
+
behaviour pass `regularize=False`. Motivated by Project Lacuna
|
|
60
|
+
dogfooding: applying real missingness generators to real UCI datasets
|
|
61
|
+
(credit_card_default × MNAR-NonLinSocial produced min_eig ≈ -0.66) was
|
|
62
|
+
hard-raising and killing the full cache build; the ridge fallback
|
|
63
|
+
keeps the test numerically well-defined with negligible statistical
|
|
64
|
+
impact, and the build proceeds.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## 2.1.0
|
|
68
|
+
|
|
69
|
+
- **`mom_mcar_test`: new method-of-moments MCAR test**
|
|
70
|
+
(``pystatistics/mvnmle/mcar_test.py``). A separate function — not
|
|
71
|
+
a new mode on ``little_mcar_test`` — because the method-of-moments
|
|
72
|
+
variant **is not Little's test**. Little (1988) specifically calls
|
|
73
|
+
for MLE plug-in estimators; swapping in pairwise-deletion sample
|
|
74
|
+
moments gives a statistic of the same shape with different
|
|
75
|
+
asymptotic properties, and calling it Little's test would be a
|
|
76
|
+
polite but concrete lie. The separate function preserves the
|
|
77
|
+
``little_mcar_test`` contract exactly (matches R ``mvnmle`` bit-
|
|
78
|
+
for-bit as before) while giving users a documented fast alternative.
|
|
79
|
+
|
|
80
|
+
End-to-end timings at 15 % MCAR:
|
|
81
|
+
|
|
82
|
+
| dataset | shape | little_mcar_test | mom_mcar_test |
|
|
83
|
+
|----------------|-----------|------------------|---------------|
|
|
84
|
+
| iris | 150 × 4 | 2.9 ms | 0.31 ms |
|
|
85
|
+
| wine | 178 × 13 | 60.9 ms | 2.17 ms |
|
|
86
|
+
| breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
|
|
87
|
+
|
|
88
|
+
For repeated-diagnostic workflows (e.g. an MCAR sweep over 3410
|
|
89
|
+
datasets), this is **1.6 minutes vs ~50 minutes** end-to-end. The
|
|
90
|
+
statistical trade-off is asymptotic efficiency: MoM is consistent
|
|
91
|
+
under the MCAR null but not asymptotically efficient, and the
|
|
92
|
+
finite-sample distribution deviates more from chi-square than
|
|
93
|
+
Little's does. The docstring spells out when to use which:
|
|
94
|
+
diagnostic screens → MoM; regulated submissions or anywhere the
|
|
95
|
+
exact asymptotic distribution matters → Little's.
|
|
96
|
+
|
|
97
|
+
Implementation details:
|
|
98
|
+
- ``_pairwise_deletion_moments``: O(n v^2) pairwise mean and
|
|
99
|
+
covariance via a single matmul. No per-column loop.
|
|
100
|
+
- ``chi_square_mcar_batched_np`` / ``_torch``: fully batched
|
|
101
|
+
chi-square assembly (batched SVD for conditioning,
|
|
102
|
+
well-conditioned patterns through batched solve, ill-conditioned
|
|
103
|
+
patterns through batched pinv as separate groups — no
|
|
104
|
+
per-pattern Python loop).
|
|
105
|
+
- ``backend`` parameter with same size-heuristic + visible-warning
|
|
106
|
+
discipline as the EM path. GPU is supported but does not
|
|
107
|
+
out-perform CPU on any tested shape — MoM's compute is small
|
|
108
|
+
enough that transfer + launch overhead loses to CPU numpy.
|
|
109
|
+
Auto-dispatch warns when this is the case.
|
|
110
|
+
- Honesty: ``MCARTestResult`` gained a ``method`` field so
|
|
111
|
+
downstream code knows which test produced a given result.
|
|
112
|
+
``little_mcar_test`` reports ``"Little (MLE plug-in)"``;
|
|
113
|
+
``mom_mcar_test`` reports ``"Method-of-moments
|
|
114
|
+
(pairwise-deletion plug-in)"``.
|
|
115
|
+
|
|
116
|
+
New tests (``tests/mvnmle/test_mom_mcar.py``, 10 tests):
|
|
117
|
+
name-honesty, MLE-vs-MoM agreement on MCAR data, correct rejection
|
|
118
|
+
on non-MCAR data, all-missing-row handling, speed guard of
|
|
119
|
+
≥ 10× over MLE on breast_cancer.
|
|
120
|
+
|
|
121
|
+
- **Fully-batched device-resident EM on GPU** (``_em_batched.py``
|
|
122
|
+
/ ``_run_em_loop_gpu``). Pre-2.1.0 the "GPU EM" path set up a
|
|
123
|
+
torch device in the constructor but none of the per-iteration
|
|
124
|
+
work actually ran on-device — the numpy E-step ran for every
|
|
125
|
+
backend, which is why pre-2.1.0 benchmarks showed identical CPU
|
|
126
|
+
and GPU timings. This release implements the real thing: one
|
|
127
|
+
batched Cholesky + one batched solve over patterns for the
|
|
128
|
+
regression betas, one batched gather + bmm over all N
|
|
129
|
+
observations for the filled data, two dense gemms for the
|
|
130
|
+
sufficient-statistic accumulators, all on-device. SQUAREM also
|
|
131
|
+
runs fully on-device.
|
|
132
|
+
|
|
133
|
+
EM-only timings (without the MCAR-assembly wrapper):
|
|
134
|
+
|
|
135
|
+
| dataset | shape | CPU EM | GPU EM | speedup |
|
|
136
|
+
|----------------|-----------|----------|----------|---------|
|
|
137
|
+
| wine | 178 × 13 | 38 ms | 24 ms | 1.6× |
|
|
138
|
+
| breast_cancer | 569 × 30 | 2142 ms | 147 ms | 14.6× |
|
|
139
|
+
|
|
140
|
+
Small-data cases (apple, iris, missvals) lose on GPU because
|
|
141
|
+
transfer + launch overhead exceeds the per-iteration work.
|
|
142
|
+
Empirically calibrated heuristic: GPU is worth it when
|
|
143
|
+
``n_obs * n_vars > 1500``.
|
|
144
|
+
|
|
145
|
+
- **Size-heuristic dispatch with Rule-1 visibility** for both EM and
|
|
146
|
+
MoM backends. When ``backend='auto'`` makes a non-obvious choice
|
|
147
|
+
(e.g. picking CPU despite GPU availability because the data are
|
|
148
|
+
too small), a ``UserWarning`` explains the decision and tells
|
|
149
|
+
users how to override. When ``backend='gpu'`` is explicitly
|
|
150
|
+
requested on small data, the request is honored (user knows best)
|
|
151
|
+
but a warning notes that CPU would likely be faster. No silent
|
|
152
|
+
fallbacks anywhere. New tests pin these behaviours.
|
|
153
|
+
|
|
154
|
+
- **Monotone-missingness closed-form MLE** (Anderson 1957; new
|
|
155
|
+
``pystatistics.mvnmle._monotone``). When the missingness pattern
|
|
156
|
+
is monotone — when variables can be ordered such that each
|
|
157
|
+
observation's missing entries form a contiguous suffix — the MVN
|
|
158
|
+
MLE has a closed form via a chain of OLS regressions, with no
|
|
159
|
+
iteration. Common on longitudinal data with attrition, panel
|
|
160
|
+
surveys with dropout, and most sequentially-administered
|
|
161
|
+
instruments. New public helpers:
|
|
162
|
+
|
|
163
|
+
- ``pystatistics.mvnmle.is_monotone(data) -> bool``
|
|
164
|
+
- ``pystatistics.mvnmle.monotone_permutation(data) -> ndarray | None``
|
|
165
|
+
- ``pystatistics.mvnmle.mlest_monotone_closed_form(data) -> (mu, sigma, n)``
|
|
166
|
+
- ``mlest(data, algorithm='monotone')`` routes through the
|
|
167
|
+
closed-form; raises ``ValidationError`` if the data are not
|
|
168
|
+
monotone (Rule 1: no silent dispatch). Users who want
|
|
169
|
+
"use the closed form when applicable, fall back otherwise"
|
|
170
|
+
should call ``is_monotone`` first and branch explicitly.
|
|
171
|
+
|
|
172
|
+
The closed-form is the exact MLE (no tolerance-bounded
|
|
173
|
+
approximation), matches R ``mvnmle`` reference output on both
|
|
174
|
+
``apple`` and ``missvals`` to machine precision, and is
|
|
175
|
+
dramatically faster than iterative algorithms at larger v
|
|
176
|
+
(a 1500 × 20 monotone dataset completes in ~2 ms vs EM's
|
|
177
|
+
~40 ms). For non-monotone random MCAR data (the common case
|
|
178
|
+
in MCAR diagnostic use), detection is cheap (~O(v² n)) and
|
|
179
|
+
correctly returns False so iterative algorithms run.
|
|
180
|
+
|
|
181
|
+
New tests (``tests/mvnmle/test_monotone.py``, 12 tests):
|
|
182
|
+
detection true-positive / true-negative on several canonical
|
|
183
|
+
shapes; closed-form vs EM agreement; permutation invariance;
|
|
184
|
+
non-monotone data raises; performance guard at v=20.
|
|
185
|
+
|
|
186
|
+
- **EM MLE: substantial real-data speedup via batched per-pattern
|
|
187
|
+
linear algebra + SQUAREM acceleration** (Project Lacuna-driven).
|
|
188
|
+
|
|
189
|
+
End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
|
|
190
|
+
|
|
191
|
+
| dataset | shape | 2.0.1 | 2.1.0 | speedup |
|
|
192
|
+
|----------------|-----------|----------|----------|---------|
|
|
193
|
+
| apple | 18 × 2 | 1.9 ms | 2.0 ms | flat |
|
|
194
|
+
| missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
|
|
195
|
+
| iris | 150 × 4 | 2.8 ms | 2.8 ms | flat |
|
|
196
|
+
| wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
|
|
197
|
+
| breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
|
|
198
|
+
|
|
199
|
+
For workloads that run MCAR repeatedly over many datasets
|
|
200
|
+
(e.g. a 3410-entry MCAR sweep), this is roughly a 1-hour reduction
|
|
201
|
+
per full pass at Lacuna's current scale.
|
|
202
|
+
|
|
203
|
+
Three changes stack:
|
|
204
|
+
|
|
205
|
+
1. **Batched per-pattern conditional parameters** (new
|
|
206
|
+
``pystatistics.mvnmle.backends._em_batched``). The E-step used
|
|
207
|
+
to loop in Python over missingness patterns, issuing a scalar
|
|
208
|
+
Cholesky + triangular solve per pattern. It now stacks all P
|
|
209
|
+
pattern-sigma submatrices into a single
|
|
210
|
+
``(P, v_max, v_max)`` tensor (identity-padded in the unused
|
|
211
|
+
slots so the Cholesky stays well-defined) and runs one batched
|
|
212
|
+
Cholesky + one batched solve for the whole iteration. The
|
|
213
|
+
accumulator loop over patterns remains in Python because
|
|
214
|
+
``n_k`` varies and full observation-level padding hurt more
|
|
215
|
+
than it helped on the representative shapes we benchmarked.
|
|
216
|
+
|
|
217
|
+
2. **SQUAREM acceleration** (Varadhan & Roland 2008; new
|
|
218
|
+
``pystatistics.mvnmle.backends._squarem``). EM's linear
|
|
219
|
+
convergence is sped up by a Steffensen-style extrapolation of
|
|
220
|
+
three consecutive EM iterates, safeguarded by a monotonicity
|
|
221
|
+
check on the observed-data log-likelihood. Typical effect on
|
|
222
|
+
well-behaved EM problems: 2–4× reduction in underlying
|
|
223
|
+
EM-step-equivalents. Preserves the MLE — the convergence
|
|
224
|
+
point is unchanged, only the path is shorter. On by default
|
|
225
|
+
via a new ``accelerate=True`` kwarg on ``EMBackend.solve``;
|
|
226
|
+
pass ``accelerate=False`` for the plain-EM reference path.
|
|
227
|
+
|
|
228
|
+
3. **Fully batched observed-data log-likelihood**
|
|
229
|
+
(``compute_loglik_batched_np``). The SQUAREM monotonicity
|
|
230
|
+
safeguard calls the log-likelihood often, so that path
|
|
231
|
+
needed to be cheap. The implementation now does one batched
|
|
232
|
+
Cholesky over all patterns for log-determinants and one
|
|
233
|
+
batched solve across all N observations for the quadratic-
|
|
234
|
+
form contribution — no per-pattern Python loop.
|
|
235
|
+
|
|
236
|
+
- **Benchmark harness** (``benchmarks/mvnmle_bench.py``). Runs the
|
|
237
|
+
five reference shapes (apple, missvals, iris, wine,
|
|
238
|
+
breast_cancer) across the (algorithm, backend) matrix and
|
|
239
|
+
prints wall-clock / iteration counts per case. Use
|
|
240
|
+
``--quick`` to skip the BFGS cases that don't converge on
|
|
241
|
+
high-$v$ data; ``--tag`` labels a run for diff against prior
|
|
242
|
+
baselines.
|
|
243
|
+
|
|
244
|
+
- **Documented why direct-BFGS is not always the right default.**
|
|
245
|
+
Internal notes and the 2.0.0 / 2.0.1 release narrative already
|
|
246
|
+
covered why ``algorithm='em'`` became the ``little_mcar_test``
|
|
247
|
+
default; this release adds the story of why batching helps EM
|
|
248
|
+
significantly but does *not* rescue direct-BFGS on realistic
|
|
249
|
+
high-$v$ data (layer-3 Hessian conditioning is parameterization-
|
|
250
|
+
invariant; batching only addresses layer-1 launch overhead).
|
|
251
|
+
See ``GPU_BACKEND_CONVENTION.md`` Section 0 for the "when to
|
|
252
|
+
add a GPU backend and when not" rule that drove the 2.0.1
|
|
253
|
+
cleanup; this release extends that logic with
|
|
254
|
+
"accelerating the algorithm by reducing iteration count
|
|
255
|
+
(SQUAREM) is cheaper than accelerating each iteration."
|
|
256
|
+
|
|
257
|
+
- **Finding: the "GPU EM" backend was never actually running on
|
|
258
|
+
GPU.** The ``device='cuda'`` / ``'mps'`` constructor flag set
|
|
259
|
+
up ``self._torch`` but none of ``_e_step`` / ``_m_step`` /
|
|
260
|
+
``_compute_loglik`` used it — the numpy path ran for every
|
|
261
|
+
backend. That's why pre-2.1.0 benchmarks showed identical
|
|
262
|
+
CPU and GPU EM timings. We attempted to implement a real
|
|
263
|
+
device-resident EM loop and found it was slower than CPU for
|
|
264
|
+
all the shapes we care about (per-pattern kernel-launch
|
|
265
|
+
overhead dominates the small per-pattern matrix work). The
|
|
266
|
+
honest answer for now is that GPU EM stays CPU-equivalent
|
|
267
|
+
by design; a future release may revisit with fully N-parallel
|
|
268
|
+
observation-level batching if a workload appears where the
|
|
269
|
+
GPU can actually win. This behaviour is unchanged from prior
|
|
270
|
+
releases — we're just documenting what was already true.
|
|
271
|
+
|
|
272
|
+
- **SQUAREM test coverage** (new ``tests/mvnmle/test_squarem.py``).
|
|
273
|
+
Four tests pinning the invariants: same MLE as plain EM on
|
|
274
|
+
apple; substantially fewer EM-equivalent steps on missvals;
|
|
275
|
+
monotonicity of log-likelihood preserved across iteration
|
|
276
|
+
caps; same MLE as plain EM on a realistic shape (sklearn
|
|
277
|
+
wine with 15 % MCAR).
|
|
278
|
+
|
|
279
|
+
|
|
3
280
|
## 2.0.1
|
|
4
281
|
|
|
5
282
|
- **GPU Backend Convention: codified when NOT to add a GPU backend**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pystatistics
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: GPU-accelerated statistical computing for Python
|
|
5
5
|
Project-URL: Homepage, https://sgcx.org/technology/pystatistics/
|
|
6
6
|
Project-URL: Documentation, https://sgcx.org/docs/pystatistics/
|
|
@@ -51,6 +51,176 @@ GPU-accelerated statistical computing for Python.
|
|
|
51
51
|
|
|
52
52
|
## What's New
|
|
53
53
|
|
|
54
|
+
### 2.2.0 — Real-data robustness from Project Lacuna dogfooding
|
|
55
|
+
|
|
56
|
+
Continuation of the 2.1.0 dogfooding track. Running `little_mcar_test`
|
|
57
|
+
and `mom_mcar_test` on 3,080 (dataset × generator) pairs drawn from 28
|
|
58
|
+
real UCI / OpenML / sklearn tabular datasets under
|
|
59
|
+
`lacuna_tabular_110` missingness generators surfaced four classes of
|
|
60
|
+
numerical failure that synthetic unit tests did not exhibit. All fixed
|
|
61
|
+
in this release; no API breaks.
|
|
62
|
+
|
|
63
|
+
**Batched MoM GPU Cholesky crash.** `chi_square_mcar_batched_torch`'s
|
|
64
|
+
fast path selected `cholesky_solve` whenever the SVD-based condition
|
|
65
|
+
number check passed, on the assumption that good conditioning implies
|
|
66
|
+
positive-definiteness. On GPU FP32, roundoff can produce covariances
|
|
67
|
+
that pass the cond-number check but have tiny negative eigenvalues —
|
|
68
|
+
Cholesky fails, the call raises `torch._C._LinAlgError`. The fast path
|
|
69
|
+
is now wrapped with `try/except` and falls back to pseudo-inverse when
|
|
70
|
+
the ``regularize`` flag allows. Surfaced on `credit_card_default` ×
|
|
71
|
+
`MNAR-NonLinSocial` during the Lacuna cache build.
|
|
72
|
+
|
|
73
|
+
**Exception-type preservation in `little_mcar_test`.** The
|
|
74
|
+
ML-estimation `try/except` at the top of `little_mcar_test` wrapped
|
|
75
|
+
*every* exception as a bare `RuntimeError` — including
|
|
76
|
+
`PyStatisticsError` subclasses. This broke the documented
|
|
77
|
+
`except PyStatisticsError:` catch pattern downstream: users falling
|
|
78
|
+
back to a sentinel on MLE failure saw their handler bypassed and the
|
|
79
|
+
full build crash. Fix: explicitly re-raise `PyStatisticsError`, and
|
|
80
|
+
use `raise ... from e` for anything else so the chain is preserved.
|
|
81
|
+
|
|
82
|
+
**`regularize=True` default on the EM path (opt-out).** `mlest`,
|
|
83
|
+
`_solve_em`, and `EMBackend.solve` gain `regularize: bool = True`,
|
|
84
|
+
mirroring the existing convention on `mom_mcar_test` and
|
|
85
|
+
`little_mcar_test`. When True, `EMBackend._ensure_pd` applies a small
|
|
86
|
+
diagonal ridge — `max(0, 1e-10 − min_eig) + 1e-12` — to the M-step
|
|
87
|
+
sigma whenever its smallest eigenvalue falls below the PD threshold,
|
|
88
|
+
rather than raising `NumericalError`. The ridge is well below any
|
|
89
|
+
statistical precision on real data — the typical case the old path
|
|
90
|
+
rejected had `min_eig ≈ 1e-13` from pure FP64 roundoff on a matrix
|
|
91
|
+
that's theoretically PSD. Dogfooding surfaced cases where `min_eig`
|
|
92
|
+
hit `−0.66` on realistic MNAR mechanisms; the ridge fallback keeps EM
|
|
93
|
+
progressing. Callers needing strict bit-for-bit behaviour pass
|
|
94
|
+
`regularize=False` to restore the old raise.
|
|
95
|
+
|
|
96
|
+
**Three additional Cholesky ridge-fallbacks** in `_em_batched.py`:
|
|
97
|
+
`e_step_full_batched_np`, `_e_step_full_torch`, and
|
|
98
|
+
`_loglik_full_batched_torch` all compute per-pattern Cholesky of
|
|
99
|
+
`sigma_oo` sub-blocks. Real tabular data can produce individual
|
|
100
|
+
sub-blocks that are numerically indefinite even when the global sigma
|
|
101
|
+
is PD (integer-encoded categoricals with heavy collinearity in the
|
|
102
|
+
intersection of a given missingness pattern's observed variables).
|
|
103
|
+
Each site now wraps Cholesky in `try/except LinAlgError` with a
|
|
104
|
+
`ridge·I` retry (ridge = 1e-10 at pattern scale; statistically
|
|
105
|
+
invisible). Also removed a dead Cholesky call in `e_step_batched_np`
|
|
106
|
+
whose factor was never used downstream — pure crash liability — and
|
|
107
|
+
added a `pinv` fallback to the `np.linalg.solve` at the same site for
|
|
108
|
+
singular sub-blocks.
|
|
109
|
+
|
|
110
|
+
**Impact.** The Project Lacuna cache build on 3,080 (dataset ×
|
|
111
|
+
generator) pairs went from crashing on the first batch containing
|
|
112
|
+
`breast_cancer` or `credit_card_default` (pre-2.2.0) to completing in
|
|
113
|
+
a single pass at 0.9% MoM sentinel rate and 16.4% MLE sentinel rate
|
|
114
|
+
(the MLE sentinels are legitimate EM non-convergence on 1000-pattern
|
|
115
|
+
datasets — not crashes). Synthetic unit tests: 125/125 mvnmle pass.
|
|
116
|
+
|
|
117
|
+
**No API breaks.** New defaults (`regularize=True`) are strictly more
|
|
118
|
+
permissive than the old raises — any caller that was crashing before
|
|
119
|
+
will now proceed with a small `UserWarning`. Callers needing strict
|
|
120
|
+
behaviour pass `regularize=False`.
|
|
121
|
+
|
|
122
|
+
### 2.1.0 — Real-data EM speedup + monotone closed-form MLE
|
|
123
|
+
|
|
124
|
+
Dogfooding via Project Lacuna surfaced that ``little_mcar_test`` on
|
|
125
|
+
realistic tabular data (sklearn's iris / wine / breast_cancer with
|
|
126
|
+
random MCAR injection) was bottlenecked by EM: the E-step was a
|
|
127
|
+
Python loop over missingness patterns, and each SQUAREM-style
|
|
128
|
+
safeguard pass re-ran a per-pattern log-likelihood. This release
|
|
129
|
+
batches both and adds Varadhan & Roland's SQUAREM acceleration.
|
|
130
|
+
|
|
131
|
+
End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
|
|
132
|
+
|
|
133
|
+
| dataset | shape | 2.0.1 | 2.1.0 | speedup |
|
|
134
|
+
|----------------|-----------|----------|----------|---------|
|
|
135
|
+
| missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
|
|
136
|
+
| wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
|
|
137
|
+
| breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
|
|
138
|
+
|
|
139
|
+
For repeated-diagnostic workflows (e.g. an MCAR sweep over several
|
|
140
|
+
thousand datasets), this turns a 3-hour run into a 2-hour run.
|
|
141
|
+
|
|
142
|
+
Three stacked improvements, all preserving bit-equivalence on the R
|
|
143
|
+
mvnmle reference cases (apple, missvals):
|
|
144
|
+
|
|
145
|
+
- **Batched per-pattern conditional parameters.** The E-step's
|
|
146
|
+
per-pattern Cholesky + triangular solve now runs as a single
|
|
147
|
+
batched kernel pair across all missingness patterns. The
|
|
148
|
+
unused padding slots are identity-filled so the Cholesky stays
|
|
149
|
+
well-defined.
|
|
150
|
+
- **SQUAREM acceleration on top of EM.** Three EM steps + one
|
|
151
|
+
Steffensen-style extrapolation, safeguarded by a monotonicity
|
|
152
|
+
check on the observed-data log-likelihood. Typical effect:
|
|
153
|
+
2–4× fewer EM-step equivalents to convergence. Convergence
|
|
154
|
+
point is the same MLE — only the path is shorter. On by
|
|
155
|
+
default; ``EMBackend.solve(..., accelerate=False)`` recovers
|
|
156
|
+
the plain-EM reference.
|
|
157
|
+
- **Fully batched log-likelihood.** The SQUAREM monotonicity
|
|
158
|
+
check calls ``loglik`` often, so it was batched too — one
|
|
159
|
+
Cholesky over all patterns, one solve across all N
|
|
160
|
+
observations, no per-pattern Python loop.
|
|
161
|
+
|
|
162
|
+
**`mom_mcar_test`: fast method-of-moments MCAR test.** A new *separate
|
|
163
|
+
function* (not a mode on ``little_mcar_test``, because the MoM variant
|
|
164
|
+
is not Little's test) that uses pairwise-deletion sample moments
|
|
165
|
+
instead of MLE plug-in. The test is consistent under MCAR but not
|
|
166
|
+
asymptotically efficient, trading a small amount of statistical
|
|
167
|
+
efficiency for dramatic speed. At 15 % MCAR on sklearn demos:
|
|
168
|
+
|
|
169
|
+
| dataset | shape | little_mcar_test | mom_mcar_test |
|
|
170
|
+
|----------------|-----------|------------------|---------------|
|
|
171
|
+
| iris | 150 × 4 | 2.9 ms | 0.31 ms |
|
|
172
|
+
| wine | 178 × 13 | 60.9 ms | 2.17 ms |
|
|
173
|
+
| breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
|
|
174
|
+
|
|
175
|
+
For a 3410-dataset MCAR sweep: **~50 minutes → ~1.6 minutes**. Use
|
|
176
|
+
``little_mcar_test`` when you need Little 1988's asymptotic
|
|
177
|
+
distribution exactly (regulated submissions, citing R reference);
|
|
178
|
+
use ``mom_mcar_test`` for high-throughput diagnostic screens. The
|
|
179
|
+
``MCARTestResult.method`` field records which test produced a given
|
|
180
|
+
result so downstream code can disambiguate without tracking the
|
|
181
|
+
calling function.
|
|
182
|
+
|
|
183
|
+
**Fully-batched device-resident EM on GPU.** Pre-2.1.0 the
|
|
184
|
+
``device='cuda'`` EM path set up a torch device but never used it —
|
|
185
|
+
numpy ran for every backend. This release implements a real
|
|
186
|
+
device-resident loop with fully batched E-step / M-step / log-
|
|
187
|
+
likelihood, SQUAREM acceleration on top, all on device. On breast-
|
|
188
|
+
cancer-scale (569 × 30) EM drops from 2142 ms CPU to 147 ms GPU
|
|
189
|
+
(14.6×). Small data remains CPU-faster; an empirical size heuristic
|
|
190
|
+
(``n * v >= 1500``) with visible dispatch warnings keeps this
|
|
191
|
+
correct in user-facing behaviour.
|
|
192
|
+
|
|
193
|
+
**Monotone-missingness closed-form MLE** (Anderson 1957). Longitudinal
|
|
194
|
+
cohorts with attrition, panel surveys with dropout, and most
|
|
195
|
+
sequentially-administered instruments produce *monotone* missingness
|
|
196
|
+
— the variables can be ordered such that each observation's missing
|
|
197
|
+
entries form a contiguous suffix. When the pattern is monotone, the
|
|
198
|
+
MVN MLE has a closed form via a chain of OLS regressions, with no
|
|
199
|
+
iteration. New helpers: ``mvnmle.is_monotone(data)``,
|
|
200
|
+
``mvnmle.monotone_permutation(data)``, and
|
|
201
|
+
``mlest(data, algorithm='monotone')``. The closed-form matches R
|
|
202
|
+
``mvnmle`` bit-for-bit on canonical datasets and is orders of
|
|
203
|
+
magnitude faster than EM on larger-v longitudinal data. Per Rule 1
|
|
204
|
+
the algorithm raises on non-monotone input rather than silently
|
|
205
|
+
falling back — call ``is_monotone`` first if you want conditional
|
|
206
|
+
dispatch.
|
|
207
|
+
|
|
208
|
+
Also in this release:
|
|
209
|
+
|
|
210
|
+
- **Benchmark harness** under ``benchmarks/mvnmle_bench.py`` for
|
|
211
|
+
tracking wall-clock and iteration counts across the reference
|
|
212
|
+
shapes; use the ``--tag`` flag to label a baseline for diff
|
|
213
|
+
against future changes.
|
|
214
|
+
- **Documented finding**: the ``device='cuda'`` EM path was never
|
|
215
|
+
actually running on the GPU prior to this release — it stored
|
|
216
|
+
a torch device but never used it. We tried to wire up a real
|
|
217
|
+
device-resident loop and found GPU is slower than CPU for all
|
|
218
|
+
shapes we tested (per-pattern launch overhead still dominates
|
|
219
|
+
the tiny per-pattern matrix work). GPU EM therefore remains
|
|
220
|
+
CPU-equivalent by design; a future release will revisit if a
|
|
221
|
+
workload appears where full observation-level batching makes
|
|
222
|
+
GPU actually win.
|
|
223
|
+
|
|
54
224
|
### 2.0.1 — GPU-backend exposure gaps and a convention rule
|
|
55
225
|
|
|
56
226
|
Two public functions had GPU-capable inner calls but no `backend=`
|
|
@@ -4,6 +4,176 @@ GPU-accelerated statistical computing for Python.
|
|
|
4
4
|
|
|
5
5
|
## What's New
|
|
6
6
|
|
|
7
|
+
### 2.2.0 — Real-data robustness from Project Lacuna dogfooding
|
|
8
|
+
|
|
9
|
+
Continuation of the 2.1.0 dogfooding track. Running `little_mcar_test`
|
|
10
|
+
and `mom_mcar_test` on 3,080 (dataset × generator) pairs drawn from 28
|
|
11
|
+
real UCI / OpenML / sklearn tabular datasets under
|
|
12
|
+
`lacuna_tabular_110` missingness generators surfaced four classes of
|
|
13
|
+
numerical failure that synthetic unit tests did not exhibit. All fixed
|
|
14
|
+
in this release; no API breaks.
|
|
15
|
+
|
|
16
|
+
**Batched MoM GPU Cholesky crash.** `chi_square_mcar_batched_torch`'s
|
|
17
|
+
fast path selected `cholesky_solve` whenever the SVD-based condition
|
|
18
|
+
number check passed, on the assumption that good conditioning implies
|
|
19
|
+
positive-definiteness. On GPU FP32, roundoff can produce covariances
|
|
20
|
+
that pass the cond-number check but have tiny negative eigenvalues —
|
|
21
|
+
Cholesky fails, the call raises `torch._C._LinAlgError`. The fast path
|
|
22
|
+
is now wrapped with `try/except` and falls back to pseudo-inverse when
|
|
23
|
+
the ``regularize`` flag allows. Surfaced on `credit_card_default` ×
|
|
24
|
+
`MNAR-NonLinSocial` during the Lacuna cache build.
|
|
25
|
+
|
|
26
|
+
**Exception-type preservation in `little_mcar_test`.** The
|
|
27
|
+
ML-estimation `try/except` at the top of `little_mcar_test` wrapped
|
|
28
|
+
*every* exception as a bare `RuntimeError` — including
|
|
29
|
+
`PyStatisticsError` subclasses. This broke the documented
|
|
30
|
+
`except PyStatisticsError:` catch pattern downstream: users falling
|
|
31
|
+
back to a sentinel on MLE failure saw their handler bypassed and the
|
|
32
|
+
full build crash. Fix: explicitly re-raise `PyStatisticsError`, and
|
|
33
|
+
use `raise ... from e` for anything else so the chain is preserved.
|
|
34
|
+
|
|
35
|
+
**`regularize=True` default on the EM path (opt-out).** `mlest`,
|
|
36
|
+
`_solve_em`, and `EMBackend.solve` gain `regularize: bool = True`,
|
|
37
|
+
mirroring the existing convention on `mom_mcar_test` and
|
|
38
|
+
`little_mcar_test`. When True, `EMBackend._ensure_pd` applies a small
|
|
39
|
+
diagonal ridge — `max(0, 1e-10 − min_eig) + 1e-12` — to the M-step
|
|
40
|
+
sigma whenever its smallest eigenvalue falls below the PD threshold,
|
|
41
|
+
rather than raising `NumericalError`. The ridge is well below any
|
|
42
|
+
statistical precision on real data — the typical case the old path
|
|
43
|
+
rejected had `min_eig ≈ 1e-13` from pure FP64 roundoff on a matrix
|
|
44
|
+
that's theoretically PSD. Dogfooding surfaced cases where `min_eig`
|
|
45
|
+
hit `−0.66` on realistic MNAR mechanisms; the ridge fallback keeps EM
|
|
46
|
+
progressing. Callers needing strict bit-for-bit behaviour pass
|
|
47
|
+
`regularize=False` to restore the old raise.
|
|
48
|
+
|
|
49
|
+
**Three additional Cholesky ridge-fallbacks** in `_em_batched.py`:
|
|
50
|
+
`e_step_full_batched_np`, `_e_step_full_torch`, and
|
|
51
|
+
`_loglik_full_batched_torch` all compute per-pattern Cholesky of
|
|
52
|
+
`sigma_oo` sub-blocks. Real tabular data can produce individual
|
|
53
|
+
sub-blocks that are numerically indefinite even when the global sigma
|
|
54
|
+
is PD (integer-encoded categoricals with heavy collinearity in the
|
|
55
|
+
intersection of a given missingness pattern's observed variables).
|
|
56
|
+
Each site now wraps Cholesky in `try/except LinAlgError` with a
|
|
57
|
+
`ridge·I` retry (ridge = 1e-10 at pattern scale; statistically
|
|
58
|
+
invisible). Also removed a dead Cholesky call in `e_step_batched_np`
|
|
59
|
+
whose factor was never used downstream — pure crash liability — and
|
|
60
|
+
added a `pinv` fallback to the `np.linalg.solve` at the same site for
|
|
61
|
+
singular sub-blocks.
|
|
62
|
+
|
|
63
|
+
**Impact.** The Project Lacuna cache build on 3,080 (dataset ×
|
|
64
|
+
generator) pairs went from crashing on the first batch containing
|
|
65
|
+
`breast_cancer` or `credit_card_default` (pre-2.2.0) to completing in
|
|
66
|
+
a single pass at 0.9% MoM sentinel rate and 16.4% MLE sentinel rate
|
|
67
|
+
(the MLE sentinels are legitimate EM non-convergence on 1000-pattern
|
|
68
|
+
datasets — not crashes). Synthetic unit tests: 125/125 mvnmle pass.
|
|
69
|
+
|
|
70
|
+
**No API breaks.** New defaults (`regularize=True`) are strictly more
|
|
71
|
+
permissive than the old raises — any caller that was crashing before
|
|
72
|
+
will now proceed with a small `UserWarning`. Callers needing strict
|
|
73
|
+
behaviour pass `regularize=False`.
|
|
74
|
+
|
|
75
|
+
### 2.1.0 — Real-data EM speedup + monotone closed-form MLE
|
|
76
|
+
|
|
77
|
+
Dogfooding via Project Lacuna surfaced that ``little_mcar_test`` on
|
|
78
|
+
realistic tabular data (sklearn's iris / wine / breast_cancer with
|
|
79
|
+
random MCAR injection) was bottlenecked by EM: the E-step was a
|
|
80
|
+
Python loop over missingness patterns, and each SQUAREM-style
|
|
81
|
+
safeguard pass re-ran a per-pattern log-likelihood. This release
|
|
82
|
+
batches both and adds Varadhan & Roland's SQUAREM acceleration.
|
|
83
|
+
|
|
84
|
+
End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
|
|
85
|
+
|
|
86
|
+
| dataset | shape | 2.0.1 | 2.1.0 | speedup |
|
|
87
|
+
|----------------|-----------|----------|----------|---------|
|
|
88
|
+
| missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
|
|
89
|
+
| wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
|
|
90
|
+
| breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
|
|
91
|
+
|
|
92
|
+
For repeated-diagnostic workflows (e.g. an MCAR sweep over several
|
|
93
|
+
thousand datasets), this turns a 3-hour run into a 2-hour run.
|
|
94
|
+
|
|
95
|
+
Three stacked improvements, all preserving bit-equivalence on the R
|
|
96
|
+
mvnmle reference cases (apple, missvals):
|
|
97
|
+
|
|
98
|
+
- **Batched per-pattern conditional parameters.** The E-step's
|
|
99
|
+
per-pattern Cholesky + triangular solve now runs as a single
|
|
100
|
+
batched kernel pair across all missingness patterns. The
|
|
101
|
+
unused padding slots are identity-filled so the Cholesky stays
|
|
102
|
+
well-defined.
|
|
103
|
+
- **SQUAREM acceleration on top of EM.** Three EM steps + one
|
|
104
|
+
Steffensen-style extrapolation, safeguarded by a monotonicity
|
|
105
|
+
check on the observed-data log-likelihood. Typical effect:
|
|
106
|
+
2–4× fewer EM-step equivalents to convergence. Convergence
|
|
107
|
+
point is the same MLE — only the path is shorter. On by
|
|
108
|
+
default; ``EMBackend.solve(..., accelerate=False)`` recovers
|
|
109
|
+
the plain-EM reference.
|
|
110
|
+
- **Fully batched log-likelihood.** The SQUAREM monotonicity
|
|
111
|
+
check calls ``loglik`` often, so it was batched too — one
|
|
112
|
+
Cholesky over all patterns, one solve across all N
|
|
113
|
+
observations, no per-pattern Python loop.
|
|
114
|
+
|
|
115
|
+
**`mom_mcar_test`: fast method-of-moments MCAR test.** A new *separate
|
|
116
|
+
function* (not a mode on ``little_mcar_test``, because the MoM variant
|
|
117
|
+
is not Little's test) that uses pairwise-deletion sample moments
|
|
118
|
+
instead of MLE plug-in. The test is consistent under MCAR but not
|
|
119
|
+
asymptotically efficient, trading a small amount of statistical
|
|
120
|
+
efficiency for dramatic speed. At 15 % MCAR on sklearn demos:
|
|
121
|
+
|
|
122
|
+
| dataset | shape | little_mcar_test | mom_mcar_test |
|
|
123
|
+
|----------------|-----------|------------------|---------------|
|
|
124
|
+
| iris | 150 × 4 | 2.9 ms | 0.31 ms |
|
|
125
|
+
| wine | 178 × 13 | 60.9 ms | 2.17 ms |
|
|
126
|
+
| breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
|
|
127
|
+
|
|
128
|
+
For a 3410-dataset MCAR sweep: **~50 minutes → ~1.6 minutes**. Use
|
|
129
|
+
``little_mcar_test`` when you need Little 1988's asymptotic
|
|
130
|
+
distribution exactly (regulated submissions, citing R reference);
|
|
131
|
+
use ``mom_mcar_test`` for high-throughput diagnostic screens. The
|
|
132
|
+
``MCARTestResult.method`` field records which test produced a given
|
|
133
|
+
result so downstream code can disambiguate without tracking the
|
|
134
|
+
calling function.
|
|
135
|
+
|
|
136
|
+
**Fully-batched device-resident EM on GPU.** Pre-2.1.0 the
|
|
137
|
+
``device='cuda'`` EM path set up a torch device but never used it —
|
|
138
|
+
numpy ran for every backend. This release implements a real
|
|
139
|
+
device-resident loop with fully batched E-step / M-step / log-
|
|
140
|
+
likelihood, SQUAREM acceleration on top, all on device. On breast-
|
|
141
|
+
cancer-scale (569 × 30) EM drops from 2142 ms CPU to 147 ms GPU
|
|
142
|
+
(14.6×). Small data remains CPU-faster; an empirical size heuristic
|
|
143
|
+
(``n * v >= 1500``) with visible dispatch warnings keeps this
|
|
144
|
+
correct in user-facing behaviour.
|
|
145
|
+
|
|
146
|
+
**Monotone-missingness closed-form MLE** (Anderson 1957). Longitudinal
|
|
147
|
+
cohorts with attrition, panel surveys with dropout, and most
|
|
148
|
+
sequentially-administered instruments produce *monotone* missingness
|
|
149
|
+
— the variables can be ordered such that each observation's missing
|
|
150
|
+
entries form a contiguous suffix. When the pattern is monotone, the
|
|
151
|
+
MVN MLE has a closed form via a chain of OLS regressions, with no
|
|
152
|
+
iteration. New helpers: ``mvnmle.is_monotone(data)``,
|
|
153
|
+
``mvnmle.monotone_permutation(data)``, and
|
|
154
|
+
``mlest(data, algorithm='monotone')``. The closed-form matches R
|
|
155
|
+
``mvnmle`` bit-for-bit on canonical datasets and is orders of
|
|
156
|
+
magnitude faster than EM on larger-v longitudinal data. Per Rule 1
|
|
157
|
+
the algorithm raises on non-monotone input rather than silently
|
|
158
|
+
falling back — call ``is_monotone`` first if you want conditional
|
|
159
|
+
dispatch.
|
|
160
|
+
|
|
161
|
+
Also in this release:
|
|
162
|
+
|
|
163
|
+
- **Benchmark harness** under ``benchmarks/mvnmle_bench.py`` for
|
|
164
|
+
tracking wall-clock and iteration counts across the reference
|
|
165
|
+
shapes; use the ``--tag`` flag to label a baseline for diff
|
|
166
|
+
against future changes.
|
|
167
|
+
- **Documented finding**: the ``device='cuda'`` EM path was never
|
|
168
|
+
actually running on the GPU prior to this release — it stored
|
|
169
|
+
a torch device but never used it. We tried to wire up a real
|
|
170
|
+
device-resident loop and found GPU is slower than CPU for all
|
|
171
|
+
shapes we tested (per-pattern launch overhead still dominates
|
|
172
|
+
the tiny per-pattern matrix work). GPU EM therefore remains
|
|
173
|
+
CPU-equivalent by design; a future release will revisit if a
|
|
174
|
+
workload appears where full observation-level batching makes
|
|
175
|
+
GPU actually win.
|
|
176
|
+
|
|
7
177
|
### 2.0.1 — GPU-backend exposure gaps and a convention rule
|
|
8
178
|
|
|
9
179
|
Two public functions had GPU-capable inner calls but no `backend=`
|