classifier-toolkit 0.3.4__tar.gz → 0.3.6__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.
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/workflows/checks.yaml +16 -2
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/PKG-INFO +2 -2
- classifier_toolkit-0.3.6/classifier_toolkit/calibration/__init__.py +34 -0
- classifier_toolkit-0.3.6/classifier_toolkit/calibration/base.py +5 -0
- classifier_toolkit-0.3.6/classifier_toolkit/calibration/ovr_calibration.py +254 -0
- classifier_toolkit-0.3.6/classifier_toolkit/calibration/reliability.py +109 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/eda_toolkit.py +6 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/visualizations.py +314 -91
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/explainability/__init__.py +1 -0
- classifier_toolkit-0.3.6/classifier_toolkit/explainability/base.py +138 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/explainability/interactions.py +34 -6
- classifier_toolkit-0.3.6/classifier_toolkit/explainability/misclassification.py +244 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/explainability/plots.py +55 -2
- classifier_toolkit-0.3.6/classifier_toolkit/explainability/toolkit.py +234 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/explainability/tree_explainer.py +49 -1
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/counter_intuitive.py +64 -6
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/predictive_power.py +162 -55
- classifier_toolkit-0.3.6/classifier_toolkit/feature_selection/utils/scoring.py +373 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/combination_search.py +78 -15
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/rfe.py +113 -32
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/hyper_parameter_tuning/tuner.py +162 -39
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/models/ensemble_methods.py +93 -30
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/utils/params.py +45 -4
- classifier_toolkit-0.3.6/docs/calibration/overview.md +53 -0
- classifier_toolkit-0.3.6/docs/changelog.md +65 -0
- classifier_toolkit-0.3.6/docs/feature_reduction/predictive_power.md +55 -0
- classifier_toolkit-0.3.6/docs/reference/calibration/ovr_calibration.md +3 -0
- classifier_toolkit-0.3.6/docs/reference/calibration/reliability.md +3 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/predictive_power.md +25 -7
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/mkdocs.yml +5 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/pyproject.toml +1 -1
- classifier_toolkit-0.3.6/tests/calibration/test_ovr_calibration.py +271 -0
- classifier_toolkit-0.3.6/tests/calibration/test_reliability.py +67 -0
- classifier_toolkit-0.3.6/tests/eda/test_visualizations.py +400 -0
- classifier_toolkit-0.3.6/tests/explainability/__init__.py +0 -0
- classifier_toolkit-0.3.6/tests/explainability/test_multiclass_e2e.py +473 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_counter_intuitive.py +104 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_predictive_power.py +193 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_combination_search.py +113 -0
- classifier_toolkit-0.3.6/tests/feature_selection/test_rfe.py +229 -0
- classifier_toolkit-0.3.6/tests/feature_selection/test_scoring.py +300 -0
- classifier_toolkit-0.3.6/tests/model_training/__init__.py +0 -0
- classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning/__init__.py +0 -0
- classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning/test_params.py +103 -0
- classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning/test_tuner.py +418 -0
- classifier_toolkit-0.3.6/tests/model_training/models/__init__.py +0 -0
- classifier_toolkit-0.3.6/tests/model_training/models/test_ensemble_methods.py +160 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/uv.lock +1 -1
- classifier_toolkit-0.3.4/classifier_toolkit/explainability/base.py +0 -60
- classifier_toolkit-0.3.4/classifier_toolkit/explainability/misclassification.py +0 -107
- classifier_toolkit-0.3.4/classifier_toolkit/explainability/toolkit.py +0 -137
- classifier_toolkit-0.3.4/classifier_toolkit/feature_selection/utils/scoring.py +0 -121
- classifier_toolkit-0.3.4/docs/changelog.md +0 -36
- classifier_toolkit-0.3.4/docs/feature_reduction/predictive_power.md +0 -34
- classifier_toolkit-0.3.4/tests/eda/test_visualizations.py +0 -116
- classifier_toolkit-0.3.4/tests/feature_selection/test_rfe.py +0 -114
- classifier_toolkit-0.3.4/tests/feature_selection/test_scoring.py +0 -70
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/pull_request_template/default.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/workflows/docs.yml +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/workflows/master.yaml +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/workflows/release.yaml +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.github/workflows/working-branch.yaml +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.gitignore +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.python-version +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/.sqlfluff +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/LICENSE +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/Makefile +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/README.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/data_partition/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/data_partition/data_preprocess.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/data_partition/optimize_data.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/data_partition/split_train_test.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/bivariate_analysis.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/feature_engineering.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/first_glance.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/univariate_analysis.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/warnings/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/warnings/automated_warnings.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/eda/warnings/default_warnings.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/base.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/correlation.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/drift.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/expert_rules.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/low_variance.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_reduction/reducer.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/base.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/embedded_methods/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/embedded_methods/elastic_net.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/feature_stability.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/meta_selector.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/utils/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/utils/data_handling.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/utils/feature_type_constraints.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/utils/plottings.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/bayesian_search.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/boruta.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/recursive_feature_eliminator.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/rfe_catboost.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/feature_selection/wrapper_methods/sequential_selection.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/hyper_parameter_tuning/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/models/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/models/base.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/classifier_toolkit/model_training/utils/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/CNAME +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/data_partition/data_preprocess.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/data_partition/optimize_data.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/data_partition/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/data_partition/split_train_test.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/bivariate_analysis.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/eda_toolkit.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/feature_engineering.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/first_glance.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/univariate_analysis.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/visualizations.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/warnings/default_warnings.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/eda/warnings/warning_system.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/examples/eda_example.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/examples/feature_selection_advanced.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/examples/feature_selection_example.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/interactions.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/misclassification.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/plots.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/toolkit.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/explainability/tree_explainer.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/correlation.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/counter_intuitive.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/drift.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/expert_rules.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/low_variance.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_reduction/reducer.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/embedded_methods/elastic_net.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/feature_stability.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/meta_selector.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/utils/data_handling.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/utils/scoring.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/bayesian_search.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/boruta.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/combination_search.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/rfe.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/feature_selection/wrapper_methods/sequential_selection.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/index.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/model_training/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/model_training/tuner.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/data_partition/data_preprocess.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/data_partition/optimize_data.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/data_partition/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/data_partition/split_train_test.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/bivariate_analysis.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/eda_toolkit.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/feature_engineering.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/first_glance.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/univariate_analysis.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/visualizations.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/warnings/default_warnings.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/eda/warnings/warning_system.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/interactions.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/misclassification.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/plots.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/toolkit.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/explainability/tree_explainer.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/base.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/correlation.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/counter_intuitive.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/drift.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/expert_rules.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/low_variance.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_reduction/reducer.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/base.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/embedded_methods/elastic_net.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/feature_stability.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/meta_selector.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/overview.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/utils/data_handling.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/utils/plottings.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/utils/scoring.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/bayesian_search.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/boruta.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/combination_search.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/rfe.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/feature_selection/wrapper_methods/sequential_selection.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/model_training/params.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/reference/tuner/tuner.md +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/docs/stylesheets/extra.css +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_bayesian_search.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_combination_feature_search.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_explainability_catboost.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_explainability_lgbm.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_feature_reduction.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_grid_search.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_model_training_catboost.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_model_training_lgbm.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_recursive_feature_eliminator.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/examples/example_train_test_partition.ipynb +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/main.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/notebooks/paylater_removed.json +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/ruff.toml +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/__init__.py +0 -0
- {classifier_toolkit-0.3.4/tests/data_partition → classifier_toolkit-0.3.6/tests/calibration}/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/conftest.py +0 -0
- {classifier_toolkit-0.3.4/tests/eda → classifier_toolkit-0.3.6/tests/data_partition}/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/data_partition/test_data_preprocess.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/data_partition/test_optimize_data.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/data_partition/test_split_train_test.py +0 -0
- {classifier_toolkit-0.3.4/tests/explainability → classifier_toolkit-0.3.6/tests/eda}/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/eda/test_bivariate_analysis.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/eda/test_feature_engineering.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/eda/test_first_glance.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/eda/test_univariate_analysis.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/eda/test_warnings.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_catboost_e2e.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_misclassification.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_plots.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_smoke.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_toolkit.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/explainability/test_tree_explainer.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_correlation.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_drift.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_expert_rules.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_low_variance.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_reducer.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_reduction/test_smoke.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/__init__.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_bayesian_search.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_boruta.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_elastic_net.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_feature_stability.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_recursive_feature_eliminator.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_rfe_catboost.py +0 -0
- {classifier_toolkit-0.3.4 → classifier_toolkit-0.3.6}/tests/feature_selection/test_sequential_selection.py +0 -0
|
@@ -91,13 +91,27 @@ jobs:
|
|
|
91
91
|
- name: Run linting
|
|
92
92
|
run: uv run make lint
|
|
93
93
|
|
|
94
|
+
discover-test-groups:
|
|
95
|
+
runs-on: default
|
|
96
|
+
outputs:
|
|
97
|
+
test-groups: ${{ steps.list.outputs.test-groups }}
|
|
98
|
+
steps:
|
|
99
|
+
- uses: actions/checkout@v6
|
|
100
|
+
|
|
101
|
+
- name: List test groups
|
|
102
|
+
id: list
|
|
103
|
+
run: |
|
|
104
|
+
groups=$(find tests -mindepth 1 -maxdepth 1 -type d ! -name '__*' ! -name '.*' -exec basename {} \; | sort | sed 's/.*/"&"/' | paste -sd, -)
|
|
105
|
+
echo "test-groups=[${groups}]" >> "$GITHUB_OUTPUT"
|
|
106
|
+
echo "Test groups: [${groups}]"
|
|
107
|
+
|
|
94
108
|
test:
|
|
95
|
-
needs: dependencies
|
|
109
|
+
needs: [dependencies, discover-test-groups]
|
|
96
110
|
runs-on: default
|
|
97
111
|
strategy:
|
|
98
112
|
fail-fast: false
|
|
99
113
|
matrix:
|
|
100
|
-
test-group:
|
|
114
|
+
test-group: ${{ fromJSON(needs.discover-test-groups.outputs.test-groups) }}
|
|
101
115
|
steps:
|
|
102
116
|
- uses: actions/checkout@v6
|
|
103
117
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: classifier-toolkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Project-URL: Documentation, https://supreme-adventure-jg5qkyr.pages.github.io/
|
|
5
5
|
Author-email: "senih.yilmaz" <senih.yilmaz@qonto.com>, "jeremy.fraoua" <jeremy.fraoua@qonto.com>, "gauthier.marquand" <gauthier.marquand@qonto.com>, "arnaud.alepee" <arnaud.alepee@qonto.com>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Probability calibration for multiclass (and binary) model output.
|
|
2
|
+
|
|
3
|
+
Public API for the OVR histogram-binning calibrator and its reliability
|
|
4
|
+
curve diagnostics — see :mod:`classifier_toolkit.calibration.ovr_calibration`
|
|
5
|
+
for details.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from importlib import import_module
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
logging.getLogger("classifier_toolkit.calibration").addHandler(logging.NullHandler())
|
|
13
|
+
|
|
14
|
+
_EXPORTS: dict[str, str] = {
|
|
15
|
+
"CalibrationError": "classifier_toolkit.calibration.base",
|
|
16
|
+
"OVRHistogramCalibrator": "classifier_toolkit.calibration.ovr_calibration",
|
|
17
|
+
"plot_reliability_curves": "classifier_toolkit.calibration.reliability",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
__all__ = list(_EXPORTS.keys())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __getattr__(name: str) -> Any: # pragma: no cover
|
|
24
|
+
module_path = _EXPORTS.get(name)
|
|
25
|
+
if module_path is None:
|
|
26
|
+
raise AttributeError(
|
|
27
|
+
f"module 'classifier_toolkit.calibration' has no attribute '{name}'"
|
|
28
|
+
)
|
|
29
|
+
module = import_module(module_path)
|
|
30
|
+
return getattr(module, name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def __dir__(): # pragma: no cover
|
|
34
|
+
return sorted(list(globals().keys()) + __all__)
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""One-vs-Rest histogram-binning calibration for multiclass probabilities.
|
|
2
|
+
|
|
3
|
+
Raw CatBoost/LightGBM scores are not guaranteed to be calibrated, which
|
|
4
|
+
matters whenever predicted probabilities are used as probabilities (pricing,
|
|
5
|
+
provisioning, or combining several models' outputs). This module calibrates
|
|
6
|
+
each class independently via histogram binning, then renormalizes the
|
|
7
|
+
calibrated row back to sum to 1.
|
|
8
|
+
|
|
9
|
+
It calibrates the output of a *single* model across the classes it predicts.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import warnings
|
|
13
|
+
from typing import Dict, Optional, Sequence, Union
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from classifier_toolkit.calibration.base import CalibrationError
|
|
18
|
+
|
|
19
|
+
ClassLabel = Union[str, int]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OVRHistogramCalibrator:
|
|
23
|
+
"""Calibrate multiclass probabilities via One-vs-Rest histogram binning.
|
|
24
|
+
|
|
25
|
+
For each class independently: bin the raw predicted probability into
|
|
26
|
+
``n_bins`` quantile-width bins, and replace it with the empirical class
|
|
27
|
+
frequency observed in that bin at fit time (histogram/binning
|
|
28
|
+
calibration — a non-parametric alternative to isotonic regression or
|
|
29
|
+
Platt scaling). Because each class is calibrated independently, the
|
|
30
|
+
calibrated row no longer sums to 1 — :meth:`transform` renormalizes it.
|
|
31
|
+
|
|
32
|
+
Sparse cells (e.g. very few observed events of a rare class in a given
|
|
33
|
+
probability bin) are shrunk toward that class's overall prevalence in
|
|
34
|
+
proportion to how little data the bin has, rather than reported as a
|
|
35
|
+
noisy raw frequency — see ``min_samples_per_bin``.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
n_bins : int, optional
|
|
40
|
+
Target number of quantile bins per class, by default 10. When many
|
|
41
|
+
scores are tied (common for a rare class, e.g. most D scores at the
|
|
42
|
+
same low value), plain quantile edges collapse; each heavily tied
|
|
43
|
+
value then gets its own bin and the remaining bins are spread over
|
|
44
|
+
the untied scores. If fewer than 3 bins can still be formed (the
|
|
45
|
+
scores take very few distinct values), a warning is raised, since
|
|
46
|
+
the calibrated output for that class is then nearly constant.
|
|
47
|
+
min_samples_per_bin : int, optional
|
|
48
|
+
Minimum training samples a bin must contain before its empirical
|
|
49
|
+
frequency is trusted as-is; bins with fewer samples are shrunk
|
|
50
|
+
toward the class's overall prevalence in proportion to
|
|
51
|
+
``n_in_bin / min_samples_per_bin``. By default 20.
|
|
52
|
+
|
|
53
|
+
Attributes
|
|
54
|
+
----------
|
|
55
|
+
classes_ : Optional[np.ndarray]
|
|
56
|
+
Class labels, in the order matching probability columns. Set by fit.
|
|
57
|
+
bin_edges_ : Dict[ClassLabel, np.ndarray]
|
|
58
|
+
Per-class quantile bin edges from fit (outer edges are +/-inf so
|
|
59
|
+
every future probability falls inside some bin).
|
|
60
|
+
bin_values_ : Dict[ClassLabel, np.ndarray]
|
|
61
|
+
Per-class calibrated (possibly shrunk) frequency for each bin.
|
|
62
|
+
class_prior_ : Dict[ClassLabel, float]
|
|
63
|
+
Per-class overall prevalence at fit time, used for shrinkage.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, n_bins: int = 10, min_samples_per_bin: int = 20) -> None:
|
|
67
|
+
self.n_bins = n_bins
|
|
68
|
+
self.min_samples_per_bin = min_samples_per_bin
|
|
69
|
+
self.classes_: Optional[np.ndarray] = None
|
|
70
|
+
self.bin_edges_: Dict[ClassLabel, np.ndarray] = {}
|
|
71
|
+
self.bin_values_: Dict[ClassLabel, np.ndarray] = {}
|
|
72
|
+
self.class_prior_: Dict[ClassLabel, float] = {}
|
|
73
|
+
|
|
74
|
+
def _quantile_edges(self, p: np.ndarray) -> np.ndarray:
|
|
75
|
+
quantiles = np.linspace(0.0, 1.0, self.n_bins + 1)
|
|
76
|
+
edges = np.unique(np.quantile(p, quantiles))
|
|
77
|
+
if len(edges) - 1 < self.n_bins:
|
|
78
|
+
edges = self._tie_aware_edges(p)
|
|
79
|
+
if len(edges) < 2:
|
|
80
|
+
edges = np.array([0.0, 1.0])
|
|
81
|
+
edges = edges.astype(float)
|
|
82
|
+
edges[0] = -np.inf
|
|
83
|
+
edges[-1] = np.inf
|
|
84
|
+
return edges
|
|
85
|
+
|
|
86
|
+
def _tie_aware_edges(self, p: np.ndarray) -> np.ndarray:
|
|
87
|
+
"""Quantile edges that give each heavily tied score its own bin.
|
|
88
|
+
|
|
89
|
+
A value is "heavily tied" when it holds more than ``1 / n_bins`` of
|
|
90
|
+
the samples, i.e. more than one quantile bin's worth. Such a value
|
|
91
|
+
collapses neighbouring quantile edges onto itself, so it is isolated
|
|
92
|
+
in its own bin (``[v, next float after v)``) and the rest of the bin
|
|
93
|
+
budget is spent on quantiles of the other scores.
|
|
94
|
+
"""
|
|
95
|
+
values, counts = np.unique(p, return_counts=True)
|
|
96
|
+
spikes = values[counts > len(p) / self.n_bins]
|
|
97
|
+
rest = p[~np.isin(p, spikes)]
|
|
98
|
+
n_rest_bins = max(self.n_bins - len(spikes), 1)
|
|
99
|
+
edges = list(spikes) + [np.nextafter(v, np.inf) for v in spikes]
|
|
100
|
+
if rest.size:
|
|
101
|
+
edges += list(np.quantile(rest, np.linspace(0.0, 1.0, n_rest_bins + 1)))
|
|
102
|
+
return np.unique(np.asarray(edges, dtype=float))
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def _bin_index(p: np.ndarray, edges: np.ndarray) -> np.ndarray:
|
|
106
|
+
return np.clip(np.digitize(p, edges[1:-1], right=False), 0, len(edges) - 2)
|
|
107
|
+
|
|
108
|
+
def fit(
|
|
109
|
+
self,
|
|
110
|
+
y_true: Union[Sequence, np.ndarray],
|
|
111
|
+
y_proba: np.ndarray,
|
|
112
|
+
classes: Optional[Sequence[ClassLabel]] = None,
|
|
113
|
+
) -> "OVRHistogramCalibrator":
|
|
114
|
+
"""Fit per-class histogram bins from raw predictions.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
y_true : array-like of shape (n_samples,)
|
|
119
|
+
True class labels.
|
|
120
|
+
y_proba : np.ndarray of shape (n_samples, n_classes)
|
|
121
|
+
Raw (uncalibrated) predicted probabilities, e.g. from
|
|
122
|
+
``model.predict_proba(X)``.
|
|
123
|
+
classes : Sequence[ClassLabel], optional
|
|
124
|
+
Class labels in the order matching ``y_proba``'s columns
|
|
125
|
+
(typically ``model.classes_``). If None, inferred as the sorted
|
|
126
|
+
unique values of ``y_true`` — only safe if every class appears
|
|
127
|
+
in ``y_true`` and ``y_proba``'s columns are already in that
|
|
128
|
+
sorted order.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
OVRHistogramCalibrator
|
|
133
|
+
The fitted calibrator.
|
|
134
|
+
"""
|
|
135
|
+
y_true = np.asarray(y_true)
|
|
136
|
+
y_proba = self._check_proba(y_proba)
|
|
137
|
+
if classes is None:
|
|
138
|
+
classes = np.unique(y_true)
|
|
139
|
+
classes = np.asarray(classes)
|
|
140
|
+
if y_proba.shape[1] != len(classes):
|
|
141
|
+
raise CalibrationError(
|
|
142
|
+
f"y_proba has {y_proba.shape[1]} columns but {len(classes)} "
|
|
143
|
+
"classes were given."
|
|
144
|
+
)
|
|
145
|
+
if y_proba.shape[0] != len(y_true):
|
|
146
|
+
raise CalibrationError(
|
|
147
|
+
f"y_proba has {y_proba.shape[0]} rows but y_true has {len(y_true)}."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
self.classes_ = classes
|
|
151
|
+
self.bin_edges_ = {}
|
|
152
|
+
self.bin_values_ = {}
|
|
153
|
+
self.class_prior_ = {}
|
|
154
|
+
|
|
155
|
+
for i, c in enumerate(classes):
|
|
156
|
+
y_bin = (y_true == c).astype(int)
|
|
157
|
+
p = y_proba[:, i]
|
|
158
|
+
prior = float(y_bin.mean()) if len(y_bin) > 0 else 0.0
|
|
159
|
+
self.class_prior_[c] = prior
|
|
160
|
+
|
|
161
|
+
edges = self._quantile_edges(p)
|
|
162
|
+
bin_idx = self._bin_index(p, edges)
|
|
163
|
+
n_populated = len(np.unique(bin_idx))
|
|
164
|
+
if n_populated < min(self.n_bins, 3):
|
|
165
|
+
warnings.warn(
|
|
166
|
+
f"Class {c!r}: only {n_populated} calibration bin(s) could "
|
|
167
|
+
f"be formed (n_bins={self.n_bins}) because its scores take "
|
|
168
|
+
"very few distinct values; its calibrated probability will "
|
|
169
|
+
"be nearly constant.",
|
|
170
|
+
stacklevel=2,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
values = np.empty(len(edges) - 1, dtype=float)
|
|
174
|
+
for b in range(len(edges) - 1):
|
|
175
|
+
mask = bin_idx == b
|
|
176
|
+
n_in_bin = int(mask.sum())
|
|
177
|
+
if n_in_bin == 0:
|
|
178
|
+
values[b] = prior
|
|
179
|
+
continue
|
|
180
|
+
observed = float(y_bin[mask].mean())
|
|
181
|
+
if n_in_bin < self.min_samples_per_bin:
|
|
182
|
+
weight = n_in_bin / self.min_samples_per_bin
|
|
183
|
+
values[b] = weight * observed + (1 - weight) * prior
|
|
184
|
+
else:
|
|
185
|
+
values[b] = observed
|
|
186
|
+
self.bin_edges_[c] = edges
|
|
187
|
+
self.bin_values_[c] = values
|
|
188
|
+
|
|
189
|
+
return self
|
|
190
|
+
|
|
191
|
+
def transform(self, y_proba: np.ndarray) -> np.ndarray:
|
|
192
|
+
"""Calibrate raw probabilities and renormalize to sum to 1.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
y_proba : np.ndarray of shape (n_samples, n_classes)
|
|
197
|
+
Raw predicted probabilities, columns matching ``classes_``.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
np.ndarray of shape (n_samples, n_classes)
|
|
202
|
+
Calibrated probabilities; each row sums to 1. A row whose
|
|
203
|
+
calibrated values are all exactly 0 (every relevant bin observed
|
|
204
|
+
no events) carries no information, so it falls back to the
|
|
205
|
+
class priors from fit.
|
|
206
|
+
"""
|
|
207
|
+
if self.classes_ is None:
|
|
208
|
+
raise CalibrationError("Calibrator is not fitted. Call fit() first.")
|
|
209
|
+
y_proba = self._check_proba(y_proba)
|
|
210
|
+
if y_proba.shape[1] != len(self.classes_):
|
|
211
|
+
raise CalibrationError(
|
|
212
|
+
f"y_proba has {y_proba.shape[1]} columns but the calibrator "
|
|
213
|
+
f"was fit on {len(self.classes_)} classes."
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
calibrated = np.empty_like(y_proba)
|
|
217
|
+
for i, c in enumerate(self.classes_):
|
|
218
|
+
edges = self.bin_edges_[c]
|
|
219
|
+
values = self.bin_values_[c]
|
|
220
|
+
bin_idx = self._bin_index(y_proba[:, i], edges)
|
|
221
|
+
calibrated[:, i] = values[bin_idx]
|
|
222
|
+
|
|
223
|
+
row_sums = calibrated.sum(axis=1, keepdims=True)
|
|
224
|
+
empty_rows = row_sums[:, 0] == 0
|
|
225
|
+
if empty_rows.any():
|
|
226
|
+
priors = np.array([self.class_prior_[c] for c in self.classes_])
|
|
227
|
+
if priors.sum() == 0:
|
|
228
|
+
priors = np.ones(len(self.classes_))
|
|
229
|
+
calibrated[empty_rows] = priors
|
|
230
|
+
row_sums = calibrated.sum(axis=1, keepdims=True)
|
|
231
|
+
return calibrated / row_sums
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def _check_proba(y_proba: np.ndarray) -> np.ndarray:
|
|
235
|
+
y_proba = np.asarray(y_proba, dtype=float)
|
|
236
|
+
if y_proba.ndim != 2:
|
|
237
|
+
raise CalibrationError(
|
|
238
|
+
f"y_proba must be 2D (n_samples, n_classes); got shape {y_proba.shape}."
|
|
239
|
+
)
|
|
240
|
+
if np.isnan(y_proba).any():
|
|
241
|
+
raise CalibrationError(
|
|
242
|
+
f"y_proba contains {int(np.isnan(y_proba).sum())} NaN value(s); "
|
|
243
|
+
"calibration needs a probability for every sample and class."
|
|
244
|
+
)
|
|
245
|
+
return y_proba
|
|
246
|
+
|
|
247
|
+
def fit_transform(
|
|
248
|
+
self,
|
|
249
|
+
y_true: Union[Sequence, np.ndarray],
|
|
250
|
+
y_proba: np.ndarray,
|
|
251
|
+
classes: Optional[Sequence[ClassLabel]] = None,
|
|
252
|
+
) -> np.ndarray:
|
|
253
|
+
"""Fit the calibrator and calibrate the same data in one step."""
|
|
254
|
+
return self.fit(y_true, y_proba, classes=classes).transform(y_proba)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Reliability curve diagnostics for OVR calibration.
|
|
2
|
+
|
|
3
|
+
One reliability (calibration) curve per class, each an
|
|
4
|
+
independent binary "class *c* vs rest" diagnostic — matching the OVR
|
|
5
|
+
calibration approach itself. Plots raw and (optionally) calibrated curves
|
|
6
|
+
together so the effect of calibration is visible directly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
from typing import Optional, Sequence, Union
|
|
11
|
+
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import numpy as np
|
|
14
|
+
from sklearn.calibration import calibration_curve
|
|
15
|
+
|
|
16
|
+
ClassLabel = Union[str, int]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def plot_reliability_curves(
|
|
20
|
+
y_true: Union[Sequence, np.ndarray],
|
|
21
|
+
y_proba_raw: np.ndarray,
|
|
22
|
+
y_proba_calibrated: Optional[np.ndarray] = None,
|
|
23
|
+
classes: Optional[Sequence[ClassLabel]] = None,
|
|
24
|
+
n_bins: int = 10,
|
|
25
|
+
pos_label: Optional[ClassLabel] = None,
|
|
26
|
+
n_cols: int = 3,
|
|
27
|
+
show: bool = True,
|
|
28
|
+
) -> plt.Figure:
|
|
29
|
+
"""Plot a reliability curve per class, one subplot each.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
y_true : array-like of shape (n_samples,)
|
|
34
|
+
True class labels.
|
|
35
|
+
y_proba_raw : np.ndarray of shape (n_samples, n_classes)
|
|
36
|
+
Raw (uncalibrated) predicted probabilities.
|
|
37
|
+
y_proba_calibrated : np.ndarray of shape (n_samples, n_classes), optional
|
|
38
|
+
Calibrated predicted probabilities (e.g. from
|
|
39
|
+
:meth:`OVRHistogramCalibrator.transform`), plotted alongside the raw
|
|
40
|
+
curve for comparison. If None, only the raw curve is shown.
|
|
41
|
+
classes : Sequence[ClassLabel], optional
|
|
42
|
+
Class labels in the order matching the probability columns. If
|
|
43
|
+
None, inferred as the sorted unique values of ``y_true``.
|
|
44
|
+
n_bins : int, optional
|
|
45
|
+
Number of quantile bins per curve, by default 10.
|
|
46
|
+
pos_label : ClassLabel, optional
|
|
47
|
+
A class of interest (e.g. the default class). If given and present
|
|
48
|
+
in ``classes``, that subplot's title is bolded in red to keep it
|
|
49
|
+
visually prominent, consistent with the rest of the multiclass
|
|
50
|
+
toolkit. By default None.
|
|
51
|
+
n_cols : int, optional
|
|
52
|
+
Subplot grid columns, by default 3.
|
|
53
|
+
show : bool, optional
|
|
54
|
+
Whether to call ``plt.show()``, by default True.
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
matplotlib.figure.Figure
|
|
59
|
+
"""
|
|
60
|
+
y_true = np.asarray(y_true)
|
|
61
|
+
y_proba_raw = np.asarray(y_proba_raw)
|
|
62
|
+
if classes is None:
|
|
63
|
+
classes = np.unique(y_true)
|
|
64
|
+
classes = list(classes)
|
|
65
|
+
n_classes = len(classes)
|
|
66
|
+
|
|
67
|
+
n_cols = min(n_cols, n_classes)
|
|
68
|
+
n_rows = math.ceil(n_classes / n_cols)
|
|
69
|
+
fig, axes = plt.subplots(
|
|
70
|
+
n_rows, n_cols, figsize=(5 * n_cols, 4 * n_rows), squeeze=False
|
|
71
|
+
)
|
|
72
|
+
axes_flat = axes.flatten()
|
|
73
|
+
|
|
74
|
+
for i, c in enumerate(classes):
|
|
75
|
+
ax = axes_flat[i]
|
|
76
|
+
y_bin = (y_true == c).astype(int)
|
|
77
|
+
|
|
78
|
+
frac_pos, mean_pred = calibration_curve(
|
|
79
|
+
y_bin, y_proba_raw[:, i], n_bins=n_bins, strategy="quantile"
|
|
80
|
+
)
|
|
81
|
+
ax.plot(mean_pred, frac_pos, marker="o", label="Raw")
|
|
82
|
+
|
|
83
|
+
if y_proba_calibrated is not None:
|
|
84
|
+
frac_pos_cal, mean_pred_cal = calibration_curve(
|
|
85
|
+
y_bin,
|
|
86
|
+
np.asarray(y_proba_calibrated)[:, i],
|
|
87
|
+
n_bins=n_bins,
|
|
88
|
+
strategy="quantile",
|
|
89
|
+
)
|
|
90
|
+
ax.plot(mean_pred_cal, frac_pos_cal, marker="s", label="Calibrated")
|
|
91
|
+
|
|
92
|
+
ax.plot([0, 1], [0, 1], linestyle="--", color="gray", label="Perfect")
|
|
93
|
+
ax.set_xlabel("Mean predicted probability")
|
|
94
|
+
ax.set_ylabel("Observed frequency")
|
|
95
|
+
title = f"Class {c}"
|
|
96
|
+
if pos_label is not None and c == pos_label:
|
|
97
|
+
ax.set_title(title, fontweight="bold", color="red")
|
|
98
|
+
else:
|
|
99
|
+
ax.set_title(title)
|
|
100
|
+
ax.legend(fontsize=8)
|
|
101
|
+
|
|
102
|
+
for i in range(n_classes, n_rows * n_cols):
|
|
103
|
+
axes_flat[i].set_visible(False)
|
|
104
|
+
|
|
105
|
+
fig.suptitle("Reliability Curves (One-vs-Rest per class)", fontsize=14, y=1.02)
|
|
106
|
+
plt.tight_layout()
|
|
107
|
+
if show:
|
|
108
|
+
plt.show()
|
|
109
|
+
return fig
|
|
@@ -49,6 +49,7 @@ class EDAToolkit:
|
|
|
49
49
|
id_column: Optional[str] = None,
|
|
50
50
|
to_be_enc: Optional[List[str]] = None,
|
|
51
51
|
warning_system: Optional[WarningSystem] = None,
|
|
52
|
+
pos_label: Optional[Union[str, int]] = None,
|
|
52
53
|
) -> None:
|
|
53
54
|
"""
|
|
54
55
|
Initialize the EDAToolkit class with data and configuration settings.
|
|
@@ -73,6 +74,10 @@ class EDAToolkit:
|
|
|
73
74
|
List of columns to be encoded, by default None.
|
|
74
75
|
warning_system : Optional[WarningSystem], optional
|
|
75
76
|
The warning system to use, by default None.
|
|
77
|
+
pos_label : Union[str, int], optional
|
|
78
|
+
The target class of interest (e.g. the default class). Forwarded
|
|
79
|
+
to :class:`Visualizations` to highlight/select that class in the
|
|
80
|
+
per-class EDA views. By default None.
|
|
76
81
|
"""
|
|
77
82
|
self.dataframe = dataframe
|
|
78
83
|
self.target_column = target_column or ""
|
|
@@ -114,6 +119,7 @@ class EDAToolkit:
|
|
|
114
119
|
self.target_column,
|
|
115
120
|
self.numerical_columns,
|
|
116
121
|
self.categorical_columns,
|
|
122
|
+
pos_label=pos_label,
|
|
117
123
|
)
|
|
118
124
|
self.univariate_analysis = UnivariateAnalysis(
|
|
119
125
|
self.dataframe, self.target_column, self.numerical_columns
|