classifier-toolkit 0.3.6__tar.gz → 0.5.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.
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/.gitignore +5 -1
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/PKG-INFO +50 -15
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/README.md +47 -13
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/data_partition/split_train_test.py +75 -154
- classifier_toolkit-0.5.0/classifier_toolkit/datasets/__init__.py +3 -0
- classifier_toolkit-0.5.0/classifier_toolkit/datasets/_demo.py +178 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/__init__.py +1 -1
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/interactions.py +39 -19
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/misclassification.py +3 -3
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/plots.py +1 -5
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/toolkit.py +17 -4
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/correlation.py +234 -43
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/counter_intuitive.py +1 -1
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/drift.py +29 -18
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/reducer.py +35 -7
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/utils/scoring.py +4 -35
- classifier_toolkit-0.5.0/classifier_toolkit/feature_selection/wrapper_methods/combination_search.py +1196 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/recursive_feature_eliminator.py +989 -25
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/rfe.py +3 -34
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/hyper_parameter_tuning/tuner.py +420 -73
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/utils/params.py +33 -9
- classifier_toolkit-0.5.0/classifier_toolkit/model_validation/__init__.py +43 -0
- classifier_toolkit-0.5.0/classifier_toolkit/model_validation/evaluator.py +1672 -0
- classifier_toolkit-0.5.0/classifier_toolkit/model_validation/model_assessment.py +975 -0
- classifier_toolkit-0.5.0/classifier_toolkit/risk_class/__init__.py +37 -0
- classifier_toolkit-0.5.0/classifier_toolkit/risk_class/risk_classes.py +1144 -0
- classifier_toolkit-0.5.0/classifier_toolkit/risk_class/risk_classes_dp.py +670 -0
- classifier_toolkit-0.5.0/examples/example_bayesian_search.ipynb +492 -0
- classifier_toolkit-0.5.0/examples/example_combination_feature_search.ipynb +537 -0
- classifier_toolkit-0.5.0/examples/example_explainability_catboost.ipynb +637 -0
- classifier_toolkit-0.5.0/examples/example_explainability_lgbm.ipynb +668 -0
- classifier_toolkit-0.5.0/examples/example_feature_reduction.ipynb +374 -0
- classifier_toolkit-0.5.0/examples/example_grid_search.ipynb +588 -0
- classifier_toolkit-0.5.0/examples/example_model_training_catboost.ipynb +194 -0
- classifier_toolkit-0.5.0/examples/example_model_training_lgbm.ipynb +186 -0
- classifier_toolkit-0.5.0/examples/example_model_validation.ipynb +369 -0
- classifier_toolkit-0.5.0/examples/example_recursive_feature_eliminator.ipynb +539 -0
- classifier_toolkit-0.5.0/examples/example_risk_classes_dp.ipynb +290 -0
- classifier_toolkit-0.5.0/examples/example_train_test_partition.ipynb +276 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/pyproject.toml +17 -2
- classifier_toolkit-0.5.0/tests/data_partition/test_split_train_test.py +247 -0
- classifier_toolkit-0.5.0/tests/datasets/test_demo_data.py +65 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_catboost_e2e.py +2 -3
- classifier_toolkit-0.5.0/tests/explainability/test_interactions.py +40 -0
- classifier_toolkit-0.5.0/tests/explainability/test_interactions_ranking.py +134 -0
- classifier_toolkit-0.5.0/tests/feature_reduction/test_correlation_tie_break.py +262 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_drift.py +112 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_reducer.py +118 -0
- classifier_toolkit-0.5.0/tests/feature_selection/test_combination_search.py +1151 -0
- classifier_toolkit-0.5.0/tests/feature_selection/test_recursive_feature_eliminator.py +1729 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_rfe.py +31 -15
- classifier_toolkit-0.5.0/tests/feature_selection/test_rfe_assessment.py +439 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_scoring.py +23 -13
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/model_training/hyper_parameter_tuning/test_params.py +62 -0
- classifier_toolkit-0.5.0/tests/model_training/hyper_parameter_tuning/test_tuner.py +1328 -0
- classifier_toolkit-0.5.0/tests/model_validation/__init__.py +0 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_compare_score_distributions.py +90 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_evaluate_risk_classes_dp.py +46 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_evaluator_multiclass.py +313 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_evaluator_threshold.py +33 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_model_assessment.py +760 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_print_full_validation_report.py +101 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_print_risk_class_validation_report.py +71 -0
- classifier_toolkit-0.5.0/tests/model_validation/test_score_distribution_psi.py +69 -0
- classifier_toolkit-0.5.0/tests/risk_class/__init__.py +0 -0
- classifier_toolkit-0.5.0/tests/risk_class/test_construct_bins_dp.py +281 -0
- classifier_toolkit-0.5.0/tests/risk_class/test_risk_classes.py +193 -0
- classifier_toolkit-0.5.0/tests/risk_class/test_validate_risk_classes.py +137 -0
- classifier_toolkit-0.3.6/.github/pull_request_template/default.md +0 -13
- classifier_toolkit-0.3.6/.github/workflows/checks.yaml +0 -148
- classifier_toolkit-0.3.6/.github/workflows/docs.yml +0 -31
- classifier_toolkit-0.3.6/.github/workflows/master.yaml +0 -48
- classifier_toolkit-0.3.6/.github/workflows/release.yaml +0 -51
- classifier_toolkit-0.3.6/.github/workflows/working-branch.yaml +0 -14
- classifier_toolkit-0.3.6/.python-version +0 -1
- classifier_toolkit-0.3.6/.sqlfluff +0 -38
- classifier_toolkit-0.3.6/Makefile +0 -22
- classifier_toolkit-0.3.6/classifier_toolkit/feature_selection/wrapper_methods/combination_search.py +0 -632
- classifier_toolkit-0.3.6/docs/CNAME +0 -1
- classifier_toolkit-0.3.6/docs/calibration/overview.md +0 -53
- classifier_toolkit-0.3.6/docs/changelog.md +0 -65
- classifier_toolkit-0.3.6/docs/data_partition/data_preprocess.md +0 -43
- classifier_toolkit-0.3.6/docs/data_partition/optimize_data.md +0 -30
- classifier_toolkit-0.3.6/docs/data_partition/overview.md +0 -30
- classifier_toolkit-0.3.6/docs/data_partition/split_train_test.md +0 -43
- classifier_toolkit-0.3.6/docs/eda/bivariate_analysis.md +0 -38
- classifier_toolkit-0.3.6/docs/eda/eda_toolkit.md +0 -65
- classifier_toolkit-0.3.6/docs/eda/feature_engineering.md +0 -60
- classifier_toolkit-0.3.6/docs/eda/first_glance.md +0 -54
- classifier_toolkit-0.3.6/docs/eda/overview.md +0 -128
- classifier_toolkit-0.3.6/docs/eda/univariate_analysis.md +0 -48
- classifier_toolkit-0.3.6/docs/eda/visualizations.md +0 -51
- classifier_toolkit-0.3.6/docs/eda/warnings/default_warnings.md +0 -45
- classifier_toolkit-0.3.6/docs/eda/warnings/warning_system.md +0 -32
- classifier_toolkit-0.3.6/docs/examples/eda_example.md +0 -71
- classifier_toolkit-0.3.6/docs/examples/feature_selection_advanced.md +0 -111
- classifier_toolkit-0.3.6/docs/examples/feature_selection_example.md +0 -123
- classifier_toolkit-0.3.6/docs/explainability/interactions.md +0 -48
- classifier_toolkit-0.3.6/docs/explainability/misclassification.md +0 -46
- classifier_toolkit-0.3.6/docs/explainability/overview.md +0 -87
- classifier_toolkit-0.3.6/docs/explainability/plots.md +0 -47
- classifier_toolkit-0.3.6/docs/explainability/toolkit.md +0 -59
- classifier_toolkit-0.3.6/docs/explainability/tree_explainer.md +0 -50
- classifier_toolkit-0.3.6/docs/feature_reduction/correlation.md +0 -34
- classifier_toolkit-0.3.6/docs/feature_reduction/counter_intuitive.md +0 -49
- classifier_toolkit-0.3.6/docs/feature_reduction/drift.md +0 -35
- classifier_toolkit-0.3.6/docs/feature_reduction/expert_rules.md +0 -26
- classifier_toolkit-0.3.6/docs/feature_reduction/low_variance.md +0 -22
- classifier_toolkit-0.3.6/docs/feature_reduction/overview.md +0 -49
- classifier_toolkit-0.3.6/docs/feature_reduction/predictive_power.md +0 -55
- classifier_toolkit-0.3.6/docs/feature_reduction/reducer.md +0 -46
- classifier_toolkit-0.3.6/docs/feature_selection/embedded_methods/elastic_net.md +0 -54
- classifier_toolkit-0.3.6/docs/feature_selection/feature_stability.md +0 -38
- classifier_toolkit-0.3.6/docs/feature_selection/meta_selector.md +0 -99
- classifier_toolkit-0.3.6/docs/feature_selection/overview.md +0 -89
- classifier_toolkit-0.3.6/docs/feature_selection/utils/data_handling.md +0 -60
- classifier_toolkit-0.3.6/docs/feature_selection/utils/scoring.md +0 -50
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/bayesian_search.md +0 -44
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/boruta.md +0 -49
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/combination_search.md +0 -39
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -35
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/rfe.md +0 -90
- classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/sequential_selection.md +0 -54
- classifier_toolkit-0.3.6/docs/index.md +0 -92
- classifier_toolkit-0.3.6/docs/model_training/overview.md +0 -51
- classifier_toolkit-0.3.6/docs/model_training/tuner.md +0 -359
- classifier_toolkit-0.3.6/docs/reference/calibration/ovr_calibration.md +0 -3
- classifier_toolkit-0.3.6/docs/reference/calibration/reliability.md +0 -3
- classifier_toolkit-0.3.6/docs/reference/data_partition/data_preprocess.md +0 -46
- classifier_toolkit-0.3.6/docs/reference/data_partition/optimize_data.md +0 -36
- classifier_toolkit-0.3.6/docs/reference/data_partition/overview.md +0 -37
- classifier_toolkit-0.3.6/docs/reference/data_partition/split_train_test.md +0 -57
- classifier_toolkit-0.3.6/docs/reference/eda/bivariate_analysis.md +0 -42
- classifier_toolkit-0.3.6/docs/reference/eda/eda_toolkit.md +0 -47
- classifier_toolkit-0.3.6/docs/reference/eda/feature_engineering.md +0 -42
- classifier_toolkit-0.3.6/docs/reference/eda/first_glance.md +0 -42
- classifier_toolkit-0.3.6/docs/reference/eda/overview.md +0 -35
- classifier_toolkit-0.3.6/docs/reference/eda/univariate_analysis.md +0 -43
- classifier_toolkit-0.3.6/docs/reference/eda/visualizations.md +0 -39
- classifier_toolkit-0.3.6/docs/reference/eda/warnings/default_warnings.md +0 -52
- classifier_toolkit-0.3.6/docs/reference/eda/warnings/warning_system.md +0 -36
- classifier_toolkit-0.3.6/docs/reference/explainability/interactions.md +0 -7
- classifier_toolkit-0.3.6/docs/reference/explainability/misclassification.md +0 -3
- classifier_toolkit-0.3.6/docs/reference/explainability/overview.md +0 -42
- classifier_toolkit-0.3.6/docs/reference/explainability/plots.md +0 -7
- classifier_toolkit-0.3.6/docs/reference/explainability/toolkit.md +0 -3
- classifier_toolkit-0.3.6/docs/reference/explainability/tree_explainer.md +0 -7
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/base.md +0 -5
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/correlation.md +0 -49
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/counter_intuitive.md +0 -40
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/drift.md +0 -75
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/expert_rules.md +0 -16
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/low_variance.md +0 -25
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/overview.md +0 -33
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/predictive_power.md +0 -68
- classifier_toolkit-0.3.6/docs/reference/feature_reduction/reducer.md +0 -121
- classifier_toolkit-0.3.6/docs/reference/feature_selection/base.md +0 -3
- classifier_toolkit-0.3.6/docs/reference/feature_selection/embedded_methods/elastic_net.md +0 -40
- classifier_toolkit-0.3.6/docs/reference/feature_selection/feature_stability.md +0 -38
- classifier_toolkit-0.3.6/docs/reference/feature_selection/meta_selector.md +0 -41
- classifier_toolkit-0.3.6/docs/reference/feature_selection/overview.md +0 -28
- classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/data_handling.md +0 -43
- classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/plottings.md +0 -5
- classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/scoring.md +0 -37
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/bayesian_search.md +0 -35
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/boruta.md +0 -34
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/combination_search.md +0 -111
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -268
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/rfe.md +0 -62
- classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/sequential_selection.md +0 -55
- classifier_toolkit-0.3.6/docs/reference/model_training/params.md +0 -5
- classifier_toolkit-0.3.6/docs/reference/tuner/tuner.md +0 -3
- classifier_toolkit-0.3.6/examples/__init__.py +0 -1
- classifier_toolkit-0.3.6/examples/example_bayesian_search.ipynb +0 -4475
- classifier_toolkit-0.3.6/examples/example_combination_feature_search.ipynb +0 -4262
- classifier_toolkit-0.3.6/examples/example_explainability_catboost.ipynb +0 -1565
- classifier_toolkit-0.3.6/examples/example_explainability_lgbm.ipynb +0 -1625
- classifier_toolkit-0.3.6/examples/example_feature_reduction.ipynb +0 -2280
- classifier_toolkit-0.3.6/examples/example_grid_search.ipynb +0 -1975
- classifier_toolkit-0.3.6/examples/example_model_training_catboost.ipynb +0 -133
- classifier_toolkit-0.3.6/examples/example_model_training_lgbm.ipynb +0 -133
- classifier_toolkit-0.3.6/examples/example_recursive_feature_eliminator.ipynb +0 -862
- classifier_toolkit-0.3.6/examples/example_train_test_partition.ipynb +0 -446
- classifier_toolkit-0.3.6/main.py +0 -6
- classifier_toolkit-0.3.6/mkdocs.yml +0 -200
- classifier_toolkit-0.3.6/notebooks/paylater_removed.json +0 -244
- classifier_toolkit-0.3.6/ruff.toml +0 -46
- classifier_toolkit-0.3.6/tests/data_partition/test_split_train_test.py +0 -122
- classifier_toolkit-0.3.6/tests/feature_selection/test_combination_search.py +0 -403
- classifier_toolkit-0.3.6/tests/feature_selection/test_recursive_feature_eliminator.py +0 -638
- classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning/test_tuner.py +0 -418
- classifier_toolkit-0.3.6/uv.lock +0 -3998
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/LICENSE +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/calibration/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/calibration/base.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/calibration/ovr_calibration.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/calibration/reliability.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/data_partition/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/data_partition/data_preprocess.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/data_partition/optimize_data.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/bivariate_analysis.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/eda_toolkit.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/feature_engineering.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/first_glance.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/univariate_analysis.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/visualizations.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/warnings/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/warnings/automated_warnings.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/eda/warnings/default_warnings.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/base.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/explainability/tree_explainer.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/base.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/expert_rules.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/low_variance.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_reduction/predictive_power.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/base.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/embedded_methods/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/embedded_methods/elastic_net.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/feature_stability.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/meta_selector.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/utils/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/utils/data_handling.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/utils/feature_type_constraints.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/utils/plottings.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/bayesian_search.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/boruta.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/rfe_catboost.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/feature_selection/wrapper_methods/sequential_selection.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/hyper_parameter_tuning/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/models/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/models/base.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/models/ensemble_methods.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/classifier_toolkit/model_training/utils/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/calibration/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/calibration/test_ovr_calibration.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/calibration/test_reliability.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/conftest.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/data_partition/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/data_partition/test_data_preprocess.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/data_partition/test_optimize_data.py +0 -0
- {classifier_toolkit-0.3.6/tests/eda → classifier_toolkit-0.5.0/tests/datasets}/__init__.py +0 -0
- {classifier_toolkit-0.3.6/tests/explainability → classifier_toolkit-0.5.0/tests/eda}/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_bivariate_analysis.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_feature_engineering.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_first_glance.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_univariate_analysis.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_visualizations.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/eda/test_warnings.py +0 -0
- {classifier_toolkit-0.3.6/tests/model_training → classifier_toolkit-0.5.0/tests/explainability}/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_misclassification.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_multiclass_e2e.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_plots.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_smoke.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_toolkit.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/explainability/test_tree_explainer.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_correlation.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_counter_intuitive.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_expert_rules.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_low_variance.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_predictive_power.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_reduction/test_smoke.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_bayesian_search.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_boruta.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_elastic_net.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_feature_stability.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_rfe_catboost.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/feature_selection/test_sequential_selection.py +0 -0
- {classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning → classifier_toolkit-0.5.0/tests/model_training}/__init__.py +0 -0
- {classifier_toolkit-0.3.6/tests/model_training/models → classifier_toolkit-0.5.0/tests/model_training/hyper_parameter_tuning}/__init__.py +0 -0
- /classifier_toolkit-0.3.6/docs/stylesheets/extra.css → /classifier_toolkit-0.5.0/tests/model_training/models/__init__.py +0 -0
- {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.0}/tests/model_training/models/test_ensemble_methods.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: classifier-toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
7
|
-
Requires-Python: <3.14,>=3.
|
|
7
|
+
Requires-Python: <3.14,>=3.10
|
|
8
8
|
Requires-Dist: catboost<2.0.0,>=1.2.2
|
|
9
9
|
Requires-Dist: category-encoders<3.0.0,>=2.6.3
|
|
10
10
|
Requires-Dist: colorama<0.5.0,>=0.4.6
|
|
@@ -18,6 +18,7 @@ Requires-Dist: polars<2.0.0,>=1.2.1
|
|
|
18
18
|
Requires-Dist: pyarrow>=18.0.0
|
|
19
19
|
Requires-Dist: scikit-learn<2.0.0,>=1.4.0
|
|
20
20
|
Requires-Dist: scipy>=1.11.0
|
|
21
|
+
Requires-Dist: seaborn<0.14.0,>=0.13.0
|
|
21
22
|
Requires-Dist: shap>=0.46.0
|
|
22
23
|
Requires-Dist: statsmodels<0.15.0,>=0.14.2
|
|
23
24
|
Requires-Dist: tabulate<0.10.0,>=0.9.0
|
|
@@ -60,13 +61,17 @@ This library is published in the PyPI directory. To install, users can run pip i
|
|
|
60
61
|
|
|
61
62
|
### Usage
|
|
62
63
|
|
|
63
|
-
This library automates binary classification
|
|
64
|
+
This library automates binary and multiclass classification workflows. It is independent of the modelled problem: the class of interest is configured through `pos_label` (the positive class for binary targets, the class of interest for multiclass ones). It includes several packages designed to address the main steps in any machine learning/data science task:
|
|
64
65
|
|
|
65
|
-
1. **EDA**: accessible via `
|
|
66
|
+
1. **EDA**: accessible via `EDAToolkit`. Provides EDA and feature engineering functionality with all necessary visualizations.
|
|
66
67
|
2. **Feature Reduction**: filter-style pre-selection pipeline (expert rules, low variance, drift, predictive power, counter-intuitive direction, high correlation).
|
|
67
68
|
3. **Feature Selection**: wrapper and embedded methods (RFE, Boruta, Sequential, Bayesian, ElasticNet, MetaSelector).
|
|
68
|
-
4. **Model Training**: accessible via `Tuner`. Hyperparameter optimization (grid search, Bayesian via Optuna) for LightGBM and CatBoost with train/val/test evaluation.
|
|
69
|
-
5.
|
|
69
|
+
4. **Model Training**: accessible via `Tuner`. Hyperparameter optimization (grid search, Bayesian via Optuna) for LightGBM and CatBoost with train/val/test evaluation, including multiclass objectives and class weights.
|
|
70
|
+
5. **Risk Class**: `RiskClassBuilderDP` / `RiskClassBuilder` turn model scores into risk classes with statistically validated, ordered event rates.
|
|
71
|
+
6. **Model Validation**: `Evaluator` computes metrics, calibration and stability checks for any model exposing `predict_proba`.
|
|
72
|
+
7. **Calibration**: `OVRHistogramCalibrator` and `plot_reliability_curves` for One-vs-Rest probability calibration.
|
|
73
|
+
8. **Explainability**: SHAP-based explanations, interactions and misclassification diagnostics.
|
|
74
|
+
9. **Data Partition**: temporal-aware train/test splitting, preprocessing and dtype optimization.
|
|
70
75
|
|
|
71
76
|
For detailed usage, refer to the documentation.
|
|
72
77
|
|
|
@@ -139,16 +144,46 @@ For detailed usage, refer to the documentation.
|
|
|
139
144
|
- **Model Training**: Hyperparameter optimization for LightGBM and CatBoost, with support for grid search and Bayesian optimization (via Optuna).
|
|
140
145
|
|
|
141
146
|
```python
|
|
142
|
-
from classifier_toolkit.model_training.hyper_parameter_tuning import Tuner
|
|
147
|
+
from classifier_toolkit.model_training.hyper_parameter_tuning.tuner import Tuner
|
|
148
|
+
|
|
149
|
+
tuner = Tuner(
|
|
150
|
+
X=X_train, y=y_train,
|
|
151
|
+
model_name="lightgbm",
|
|
152
|
+
X_val=X_val, y_val=y_val,
|
|
153
|
+
X_test=X_test, y_test=y_test,
|
|
154
|
+
search_method="bayesian",
|
|
155
|
+
n_trials=50,
|
|
156
|
+
optimization_metric="prauc",
|
|
157
|
+
)
|
|
158
|
+
result = tuner.tune()
|
|
159
|
+
|
|
160
|
+
best_model = result["best_model"]
|
|
161
|
+
result["trials_results"] # full trial results (DataFrame)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Reported metrics are `auc`, `prauc`, `ks`, `log_loss` and `brier` (`ks`/`brier` are binary-only). Custom parameter search spaces can be defined via `ModelParams` and `ParamRange`.
|
|
165
|
+
|
|
166
|
+
- **Risk Class**: Builds risk classes from model scores. `RiskClassBuilderDP` searches bin edges with dynamic programming so that each class' observed event rate falls in a target band (`target_ranges`, required), then checks that adjacent classes are statistically distinguishable; `RiskClassBuilder` discovers classes with KMeans.
|
|
143
167
|
|
|
144
|
-
|
|
145
|
-
|
|
168
|
+
```python
|
|
169
|
+
from classifier_toolkit.risk_class import RiskClassBuilderDP
|
|
146
170
|
|
|
147
|
-
|
|
148
|
-
|
|
171
|
+
builder = RiskClassBuilderDP(
|
|
172
|
+
target_col="target",
|
|
173
|
+
target_ranges=[(0.00, 0.02), (0.02, 0.05), (0.05, 0.10)],
|
|
174
|
+
min_obs_per_bin=200,
|
|
175
|
+
)
|
|
176
|
+
result = builder.build(train_proba, y_train)
|
|
177
|
+
print(result.bins, result.n_classes)
|
|
149
178
|
```
|
|
150
179
|
|
|
151
|
-
|
|
180
|
+
- **Model Validation**: `Evaluator` evaluates any model with `predict_proba` (metrics, ROC/PR/calibration/threshold plots), `score_distribution_psi` and `compare_score_distributions` compare a reference score distribution with a current one, and `evaluate_risk_classes_dp` checks calibration within each risk class.
|
|
181
|
+
|
|
182
|
+
- **Calibration**: `OVRHistogramCalibrator` calibrates multiclass (or binary) probabilities One-vs-Rest with histogram binning; `plot_reliability_curves` shows raw vs calibrated reliability per class.
|
|
183
|
+
|
|
184
|
+
- **Explainability**: `TreeSHAPExplainer`, `ExplainabilityToolkit`, SHAP plots, pairwise interaction analysis and a `MisclassificationAnalyzer` that explains confusion-matrix quadrants (per-class SHAP for multiclass models).
|
|
185
|
+
|
|
186
|
+
- **Data Partition**: Temporal-aware train/test splitting, preprocessing helpers and dtype optimization.
|
|
152
187
|
|
|
153
188
|
### Development & CI/CD
|
|
154
189
|
|
|
@@ -162,8 +197,8 @@ This project uses modern tooling for fast and efficient development workflows:
|
|
|
162
197
|
#### CI/CD Pipeline
|
|
163
198
|
Our CI/CD pipeline is optimized for speed and efficiency:
|
|
164
199
|
|
|
165
|
-
- **Parallel Test Execution**:
|
|
166
|
-
- **Shared Caching**:
|
|
200
|
+
- **Parallel Test Execution**: One test job per directory under `tests/` (discovered automatically, so new test groups are picked up without editing the workflow), all running simultaneously
|
|
201
|
+
- **Shared Caching**: The parallel jobs share the same dependency cache, avoiding duplicate downloads
|
|
167
202
|
- **Smart Test Reruns**: Failed tests run first (`pytest --lf --ff`) for faster feedback on fixes
|
|
168
203
|
- **Master Protection**: Build tests only run on `master` branch and PRs targeting `master`, saving CI resources on feature branches
|
|
169
204
|
- **Automatic Linting**: Code quality checks (Ruff, SQLFluff) run on every push
|
|
@@ -188,5 +223,5 @@ uv build
|
|
|
188
223
|
|
|
189
224
|
### Future Work
|
|
190
225
|
The next planned improvements and additions to the library include:
|
|
191
|
-
*
|
|
226
|
+
* Extending the evaluation and reporting tools in `model_validation` (more checks and report formats).
|
|
192
227
|
* Expanding documentation to include architecture diagrams and detailed usage examples.
|
|
@@ -29,13 +29,17 @@ This library is published in the PyPI directory. To install, users can run pip i
|
|
|
29
29
|
|
|
30
30
|
### Usage
|
|
31
31
|
|
|
32
|
-
This library automates binary classification
|
|
32
|
+
This library automates binary and multiclass classification workflows. It is independent of the modelled problem: the class of interest is configured through `pos_label` (the positive class for binary targets, the class of interest for multiclass ones). It includes several packages designed to address the main steps in any machine learning/data science task:
|
|
33
33
|
|
|
34
|
-
1. **EDA**: accessible via `
|
|
34
|
+
1. **EDA**: accessible via `EDAToolkit`. Provides EDA and feature engineering functionality with all necessary visualizations.
|
|
35
35
|
2. **Feature Reduction**: filter-style pre-selection pipeline (expert rules, low variance, drift, predictive power, counter-intuitive direction, high correlation).
|
|
36
36
|
3. **Feature Selection**: wrapper and embedded methods (RFE, Boruta, Sequential, Bayesian, ElasticNet, MetaSelector).
|
|
37
|
-
4. **Model Training**: accessible via `Tuner`. Hyperparameter optimization (grid search, Bayesian via Optuna) for LightGBM and CatBoost with train/val/test evaluation.
|
|
38
|
-
5.
|
|
37
|
+
4. **Model Training**: accessible via `Tuner`. Hyperparameter optimization (grid search, Bayesian via Optuna) for LightGBM and CatBoost with train/val/test evaluation, including multiclass objectives and class weights.
|
|
38
|
+
5. **Risk Class**: `RiskClassBuilderDP` / `RiskClassBuilder` turn model scores into risk classes with statistically validated, ordered event rates.
|
|
39
|
+
6. **Model Validation**: `Evaluator` computes metrics, calibration and stability checks for any model exposing `predict_proba`.
|
|
40
|
+
7. **Calibration**: `OVRHistogramCalibrator` and `plot_reliability_curves` for One-vs-Rest probability calibration.
|
|
41
|
+
8. **Explainability**: SHAP-based explanations, interactions and misclassification diagnostics.
|
|
42
|
+
9. **Data Partition**: temporal-aware train/test splitting, preprocessing and dtype optimization.
|
|
39
43
|
|
|
40
44
|
For detailed usage, refer to the documentation.
|
|
41
45
|
|
|
@@ -108,16 +112,46 @@ For detailed usage, refer to the documentation.
|
|
|
108
112
|
- **Model Training**: Hyperparameter optimization for LightGBM and CatBoost, with support for grid search and Bayesian optimization (via Optuna).
|
|
109
113
|
|
|
110
114
|
```python
|
|
111
|
-
from classifier_toolkit.model_training.hyper_parameter_tuning import Tuner
|
|
115
|
+
from classifier_toolkit.model_training.hyper_parameter_tuning.tuner import Tuner
|
|
116
|
+
|
|
117
|
+
tuner = Tuner(
|
|
118
|
+
X=X_train, y=y_train,
|
|
119
|
+
model_name="lightgbm",
|
|
120
|
+
X_val=X_val, y_val=y_val,
|
|
121
|
+
X_test=X_test, y_test=y_test,
|
|
122
|
+
search_method="bayesian",
|
|
123
|
+
n_trials=50,
|
|
124
|
+
optimization_metric="prauc",
|
|
125
|
+
)
|
|
126
|
+
result = tuner.tune()
|
|
127
|
+
|
|
128
|
+
best_model = result["best_model"]
|
|
129
|
+
result["trials_results"] # full trial results (DataFrame)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Reported metrics are `auc`, `prauc`, `ks`, `log_loss` and `brier` (`ks`/`brier` are binary-only). Custom parameter search spaces can be defined via `ModelParams` and `ParamRange`.
|
|
133
|
+
|
|
134
|
+
- **Risk Class**: Builds risk classes from model scores. `RiskClassBuilderDP` searches bin edges with dynamic programming so that each class' observed event rate falls in a target band (`target_ranges`, required), then checks that adjacent classes are statistically distinguishable; `RiskClassBuilder` discovers classes with KMeans.
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
136
|
+
```python
|
|
137
|
+
from classifier_toolkit.risk_class import RiskClassBuilderDP
|
|
115
138
|
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
builder = RiskClassBuilderDP(
|
|
140
|
+
target_col="target",
|
|
141
|
+
target_ranges=[(0.00, 0.02), (0.02, 0.05), (0.05, 0.10)],
|
|
142
|
+
min_obs_per_bin=200,
|
|
143
|
+
)
|
|
144
|
+
result = builder.build(train_proba, y_train)
|
|
145
|
+
print(result.bins, result.n_classes)
|
|
118
146
|
```
|
|
119
147
|
|
|
120
|
-
|
|
148
|
+
- **Model Validation**: `Evaluator` evaluates any model with `predict_proba` (metrics, ROC/PR/calibration/threshold plots), `score_distribution_psi` and `compare_score_distributions` compare a reference score distribution with a current one, and `evaluate_risk_classes_dp` checks calibration within each risk class.
|
|
149
|
+
|
|
150
|
+
- **Calibration**: `OVRHistogramCalibrator` calibrates multiclass (or binary) probabilities One-vs-Rest with histogram binning; `plot_reliability_curves` shows raw vs calibrated reliability per class.
|
|
151
|
+
|
|
152
|
+
- **Explainability**: `TreeSHAPExplainer`, `ExplainabilityToolkit`, SHAP plots, pairwise interaction analysis and a `MisclassificationAnalyzer` that explains confusion-matrix quadrants (per-class SHAP for multiclass models).
|
|
153
|
+
|
|
154
|
+
- **Data Partition**: Temporal-aware train/test splitting, preprocessing helpers and dtype optimization.
|
|
121
155
|
|
|
122
156
|
### Development & CI/CD
|
|
123
157
|
|
|
@@ -131,8 +165,8 @@ This project uses modern tooling for fast and efficient development workflows:
|
|
|
131
165
|
#### CI/CD Pipeline
|
|
132
166
|
Our CI/CD pipeline is optimized for speed and efficiency:
|
|
133
167
|
|
|
134
|
-
- **Parallel Test Execution**:
|
|
135
|
-
- **Shared Caching**:
|
|
168
|
+
- **Parallel Test Execution**: One test job per directory under `tests/` (discovered automatically, so new test groups are picked up without editing the workflow), all running simultaneously
|
|
169
|
+
- **Shared Caching**: The parallel jobs share the same dependency cache, avoiding duplicate downloads
|
|
136
170
|
- **Smart Test Reruns**: Failed tests run first (`pytest --lf --ff`) for faster feedback on fixes
|
|
137
171
|
- **Master Protection**: Build tests only run on `master` branch and PRs targeting `master`, saving CI resources on feature branches
|
|
138
172
|
- **Automatic Linting**: Code quality checks (Ruff, SQLFluff) run on every push
|
|
@@ -157,5 +191,5 @@ uv build
|
|
|
157
191
|
|
|
158
192
|
### Future Work
|
|
159
193
|
The next planned improvements and additions to the library include:
|
|
160
|
-
*
|
|
194
|
+
* Extending the evaluation and reporting tools in `model_validation` (more checks and report formats).
|
|
161
195
|
* Expanding documentation to include architecture diagrams and detailed usage examples.
|
|
@@ -11,200 +11,121 @@ def split_data_recent_orgs(
|
|
|
11
11
|
date_col="observation_date",
|
|
12
12
|
):
|
|
13
13
|
"""
|
|
14
|
-
Split data into train and test sets
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
Split data into train and test sets on the most recent entities.
|
|
15
|
+
|
|
16
|
+
Entities (``org_id_col``) are ordered by their first observation date, and
|
|
17
|
+
the most recent ones go to the test set, so the test set mimics entities
|
|
18
|
+
the model will meet after deployment. The number of test entities is
|
|
19
|
+
``test_size`` of all entities, adjusted as little as possible so that the
|
|
20
|
+
train and test event rates differ by at most ``rate_tolerance``: sizes are
|
|
21
|
+
tried from the target outwards (n, n-1, n+1, n-2, ...) within +/-30% of
|
|
22
|
+
it (at least +/-5), and the first one within tolerance is kept. If none
|
|
23
|
+
is, the size with the smallest event-rate difference is used. The target
|
|
24
|
+
is ``round(test_size * n_entities)``, at least 1.
|
|
18
25
|
|
|
19
26
|
Parameters:
|
|
20
27
|
-----------
|
|
21
28
|
df : pandas.DataFrame
|
|
22
29
|
The input dataframe
|
|
23
30
|
test_size : float, default=0.2
|
|
24
|
-
|
|
31
|
+
Share of **entities** (not rows) put in the test set. Recent entities
|
|
32
|
+
usually have fewer observations, so the test share of rows is lower.
|
|
25
33
|
rate_tolerance : float, default=0.05
|
|
26
|
-
Maximum
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
Maximum absolute difference between the train and test event rates
|
|
35
|
+
(``0.05`` = 5 percentage points; use a value in proportion to the
|
|
36
|
+
event rate).
|
|
29
37
|
label_col : str, default='default_label'
|
|
30
|
-
Column containing the binary
|
|
38
|
+
Column containing the binary (0/1) target
|
|
31
39
|
org_id_col : str, default='org_id'
|
|
32
|
-
Column containing
|
|
40
|
+
Column containing the entity IDs. Entities that share a first
|
|
41
|
+
observation date are ordered by ID, so the IDs must be mutually
|
|
42
|
+
comparable (not a mix of ``int`` and ``str``).
|
|
33
43
|
date_col : str, default='observation_date'
|
|
34
44
|
Column containing the observation dates
|
|
35
45
|
|
|
36
46
|
Returns:
|
|
37
47
|
--------
|
|
38
48
|
tuple
|
|
39
|
-
(train_df, test_df)
|
|
49
|
+
``(train_df, test_df, stats)``, where ``stats`` is the same dict as
|
|
50
|
+
the other splitters return (``train_orgs``, ``test_orgs``,
|
|
51
|
+
``train_records``, ``test_records``, ``train_target_rate``,
|
|
52
|
+
``test_target_rate``, ``target_rate_diff``, ...).
|
|
40
53
|
"""
|
|
41
|
-
# Ensure date column is datetime
|
|
42
54
|
df = df.copy()
|
|
43
55
|
if not pd.api.types.is_datetime64_dtype(df[date_col]):
|
|
44
56
|
df[date_col] = pd.to_datetime(df[date_col])
|
|
45
57
|
|
|
46
|
-
#
|
|
58
|
+
# First observation date of each entity, oldest first. The entity ID
|
|
59
|
+
# breaks ties, so which entities of a same-date group end up in test is
|
|
60
|
+
# deterministic.
|
|
47
61
|
org_first_dates = (
|
|
48
62
|
df.groupby(org_id_col)[date_col]
|
|
49
63
|
.min()
|
|
50
64
|
.reset_index()
|
|
51
|
-
.sort_values(date_col,
|
|
65
|
+
.sort_values([date_col, org_id_col], kind="stable")
|
|
52
66
|
)
|
|
53
|
-
|
|
54
|
-
# Calculate number of organizations for test set
|
|
55
67
|
total_orgs = len(org_first_dates)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
if total_orgs < 2:
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"split_data_recent_orgs needs at least 2 entities in {org_id_col!r}, "
|
|
71
|
+
f"got {total_orgs}."
|
|
72
|
+
)
|
|
73
|
+
n_test_orgs = max(1, round(total_orgs * test_size))
|
|
62
74
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
75
|
+
print("=== RECENT ENTITIES SPLIT WITH RATE TOLERANCE ===")
|
|
76
|
+
print(f"Test size target: {test_size:.1%} of {total_orgs} entities")
|
|
77
|
+
print(f"Rate tolerance: {rate_tolerance:.2%}")
|
|
66
78
|
|
|
67
|
-
#
|
|
79
|
+
# Sizes from the target outwards, so the first one within tolerance is
|
|
80
|
+
# the closest to the requested test_size.
|
|
68
81
|
search_range = max(5, int(n_test_orgs * 0.3))
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
test_orgs_data = org_first_dates.tail(test_org_count)
|
|
79
|
-
|
|
80
|
-
# Create temporary splits
|
|
81
|
-
temp_train = df[~df[org_id_col].isin(test_orgs_data[org_id_col].values)]
|
|
82
|
-
temp_test = df[df[org_id_col].isin(test_orgs_data[org_id_col].values)]
|
|
83
|
-
|
|
84
|
-
if len(temp_train) == 0 or len(temp_test) == 0:
|
|
82
|
+
low = max(1, n_test_orgs - search_range)
|
|
83
|
+
high = min(total_orgs - 1, n_test_orgs + search_range)
|
|
84
|
+
candidates = sorted(range(low, high + 1), key=lambda n: (abs(n - n_test_orgs), n))
|
|
85
|
+
|
|
86
|
+
best_count, best_rate_diff = None, float("inf")
|
|
87
|
+
for test_org_count in candidates:
|
|
88
|
+
test_ids = org_first_dates[org_id_col].tail(test_org_count).to_numpy()
|
|
89
|
+
is_test = df[org_id_col].isin(test_ids)
|
|
90
|
+
if is_test.all() or not is_test.any():
|
|
85
91
|
continue
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
test_rate = temp_test[label_col].mean()
|
|
90
|
-
rate_diff = abs(train_rate - test_rate)
|
|
91
|
-
|
|
92
|
-
# Check if this split is better
|
|
92
|
+
rate_diff = abs(
|
|
93
|
+
df.loc[~is_test, label_col].mean() - df.loc[is_test, label_col].mean()
|
|
94
|
+
)
|
|
93
95
|
if rate_diff < best_rate_diff:
|
|
94
|
-
best_rate_diff = rate_diff
|
|
95
|
-
best_split = {
|
|
96
|
-
"test_orgs_data": test_orgs_data,
|
|
97
|
-
"train_rate": train_rate,
|
|
98
|
-
"test_rate": test_rate,
|
|
99
|
-
"rate_diff": rate_diff,
|
|
100
|
-
"test_org_count": test_org_count,
|
|
101
|
-
"actual_test_size": len(temp_test) / len(df),
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# Stop if we found an acceptable split
|
|
96
|
+
best_count, best_rate_diff = test_org_count, rate_diff
|
|
105
97
|
if rate_diff <= rate_tolerance:
|
|
106
98
|
print(
|
|
107
|
-
f"
|
|
99
|
+
f"Found a balanced split at {test_org_count} test entities "
|
|
100
|
+
f"(event-rate difference: {rate_diff:.4f})"
|
|
108
101
|
)
|
|
109
102
|
break
|
|
103
|
+
else:
|
|
104
|
+
if best_count is None:
|
|
105
|
+
best_count = n_test_orgs
|
|
106
|
+
print("Could not find any valid split; using the target size.")
|
|
107
|
+
else:
|
|
108
|
+
print(
|
|
109
|
+
f"Best achievable event-rate difference: {best_rate_diff:.4f} "
|
|
110
|
+
f"(exceeds the tolerance {rate_tolerance:.4f}); using "
|
|
111
|
+
f"{best_count} test entities."
|
|
112
|
+
)
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"test_org_count": n_test_orgs,
|
|
116
|
-
}
|
|
117
|
-
print("⚠️ Could not find any valid split. Using target split.")
|
|
118
|
-
elif best_rate_diff > rate_tolerance:
|
|
119
|
-
print(
|
|
120
|
-
f"⚠️ Best achievable rate difference: {best_rate_diff:.4f} (exceeds tolerance: {rate_tolerance:.4f})"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
# Use the best split found
|
|
124
|
-
test_orgs_data = best_split["test_orgs_data"]
|
|
125
|
-
|
|
126
|
-
# Split data into train and test
|
|
127
|
-
train_df = df[~df[org_id_col].isin(test_orgs_data[org_id_col].values)].copy()
|
|
128
|
-
test_df = df[df[org_id_col].isin(test_orgs_data[org_id_col].values)].copy()
|
|
129
|
-
|
|
130
|
-
# Calculate statistics
|
|
131
|
-
total_orgs = df[org_id_col].nunique()
|
|
132
|
-
total_records = len(df)
|
|
133
|
-
total_pos = df[df[label_col] == 1].shape[0]
|
|
134
|
-
total_neg = df[df[label_col] == 0].shape[0]
|
|
135
|
-
|
|
136
|
-
train_orgs = train_df[org_id_col].nunique()
|
|
137
|
-
train_records = len(train_df)
|
|
138
|
-
train_pos = train_df[train_df[label_col] == 1].shape[0]
|
|
139
|
-
train_neg = train_df[train_df[label_col] == 0].shape[0]
|
|
140
|
-
|
|
141
|
-
test_orgs = test_df[org_id_col].nunique()
|
|
142
|
-
test_records = len(test_df)
|
|
143
|
-
test_pos = test_df[test_df[label_col] == 1].shape[0]
|
|
144
|
-
test_neg = test_df[test_df[label_col] == 0].shape[0]
|
|
145
|
-
|
|
146
|
-
# Verify no overlap
|
|
147
|
-
train_org_set = set(train_df[org_id_col].unique())
|
|
148
|
-
test_org_set = set(test_df[org_id_col].unique())
|
|
149
|
-
overlap = train_org_set.intersection(test_org_set)
|
|
150
|
-
|
|
151
|
-
# Print statistics
|
|
152
|
-
print("\n=== FINAL SPLIT STATISTICS ===")
|
|
153
|
-
print(f"Test organizations: {test_orgs} ({test_orgs / total_orgs:.1%})")
|
|
154
|
-
print(f"Train organizations: {train_orgs} ({train_orgs / total_orgs:.1%})")
|
|
155
|
-
|
|
156
|
-
print(f"\nTotal records: {total_records}")
|
|
157
|
-
print(f"Train records: {train_records} ({train_records / total_records:.2%})")
|
|
158
|
-
print(f"Test records: {test_records} ({test_records / total_records:.2%})")
|
|
159
|
-
|
|
160
|
-
print("\nPositive samples:")
|
|
161
|
-
print(f"Total: {total_pos}")
|
|
162
|
-
print(f"Train: {train_pos} ({train_pos / total_pos:.2%})")
|
|
163
|
-
print(f"Test: {test_pos} ({test_pos / total_pos:.2%})")
|
|
164
|
-
|
|
165
|
-
print("\nNegative samples:")
|
|
166
|
-
print(f"Total: {total_neg}")
|
|
167
|
-
print(f"Train: {train_neg} ({train_neg / total_neg:.2%})")
|
|
168
|
-
print(f"Test: {test_neg} ({test_neg / total_neg:.2%})")
|
|
169
|
-
|
|
170
|
-
print("\nDefault rates:")
|
|
171
|
-
print(f"Overall: {df[label_col].mean():.4f}")
|
|
172
|
-
print(f"Train: {train_df[label_col].mean():.4f}")
|
|
173
|
-
print(f"Test: {test_df[label_col].mean():.4f}")
|
|
174
|
-
print(
|
|
175
|
-
f"Difference: {abs(train_df[label_col].mean() - test_df[label_col].mean()):.4f}"
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
print(f"\nOrganization overlap: {len(overlap)} organizations (should be 0)")
|
|
114
|
+
test_orgs_data = org_first_dates.tail(best_count)
|
|
115
|
+
is_test = df[org_id_col].isin(test_orgs_data[org_id_col].to_numpy())
|
|
116
|
+
train_df = df[~is_test].copy()
|
|
117
|
+
test_df = df[is_test].copy()
|
|
179
118
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"Cut-off date for splitting (earliest test org first loan):",
|
|
183
|
-
test_orgs_data[date_col].min().strftime("%Y-%m-%d"),
|
|
184
|
-
)
|
|
185
|
-
print(
|
|
186
|
-
f"Training orgs (first loan): {train_df.groupby(org_id_col)[date_col].min().min().strftime('%Y-%m-%d')} to {train_df.groupby(org_id_col)[date_col].min().max().strftime('%Y-%m-%d')}"
|
|
187
|
-
)
|
|
188
|
-
print(
|
|
189
|
-
f"Testing orgs (first loan): {test_df.groupby(org_id_col)[date_col].min().min().strftime('%Y-%m-%d')} to {test_df.groupby(org_id_col)[date_col].min().max().strftime('%Y-%m-%d')}"
|
|
190
|
-
)
|
|
191
|
-
print(
|
|
192
|
-
f"Training all observations: {train_df[date_col].min().strftime('%Y-%m-%d')} to {train_df[date_col].max().strftime('%Y-%m-%d')}"
|
|
119
|
+
stats = _calculate_split_statistics(
|
|
120
|
+
df, train_df, test_df, label_col, org_id_col, date_col
|
|
193
121
|
)
|
|
122
|
+
overlap = set(train_df[org_id_col]) & set(test_df[org_id_col])
|
|
123
|
+
print(f"\nEntity overlap: {len(overlap)} (should be 0)")
|
|
194
124
|
print(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return (
|
|
199
|
-
train_df,
|
|
200
|
-
test_df,
|
|
201
|
-
(
|
|
202
|
-
train_df.shape,
|
|
203
|
-
test_df.shape,
|
|
204
|
-
train_df[train_df[label_col] == 1].shape,
|
|
205
|
-
test_df[test_df[label_col] == 1].shape,
|
|
206
|
-
),
|
|
125
|
+
"Cut-off (first observation of the earliest test entity): "
|
|
126
|
+
f"{test_orgs_data[date_col].min():%Y-%m-%d}"
|
|
207
127
|
)
|
|
128
|
+
return train_df, test_df, stats
|
|
208
129
|
|
|
209
130
|
|
|
210
131
|
def split_data_stratified_by_org(
|