classifier-toolkit 0.3.6__tar.gz → 0.5.1__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.
Files changed (281) hide show
  1. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/.gitignore +5 -1
  2. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/PKG-INFO +50 -15
  3. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/README.md +47 -13
  4. classifier_toolkit-0.5.1/classifier_toolkit/_typing.py +6 -0
  5. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/calibration/ovr_calibration.py +1 -2
  6. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/calibration/reliability.py +1 -1
  7. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/data_partition/split_train_test.py +75 -154
  8. classifier_toolkit-0.5.1/classifier_toolkit/datasets/__init__.py +3 -0
  9. classifier_toolkit-0.5.1/classifier_toolkit/datasets/_demo.py +178 -0
  10. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/eda_toolkit.py +3 -1
  11. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/visualizations.py +4 -2
  12. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/__init__.py +1 -1
  13. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/base.py +5 -3
  14. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/interactions.py +39 -19
  15. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/misclassification.py +5 -4
  16. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/plots.py +3 -6
  17. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/toolkit.py +19 -5
  18. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/explainability/tree_explainer.py +3 -2
  19. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/correlation.py +419 -78
  20. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/counter_intuitive.py +5 -4
  21. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/drift.py +29 -18
  22. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/reducer.py +58 -9
  23. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/utils/scoring.py +8 -37
  24. classifier_toolkit-0.5.1/classifier_toolkit/feature_selection/wrapper_methods/combination_search.py +1196 -0
  25. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/recursive_feature_eliminator.py +1084 -36
  26. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/rfe.py +6 -36
  27. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/hyper_parameter_tuning/tuner.py +482 -75
  28. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/models/ensemble_methods.py +3 -2
  29. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/utils/params.py +33 -9
  30. classifier_toolkit-0.5.1/classifier_toolkit/model_validation/__init__.py +43 -0
  31. classifier_toolkit-0.5.1/classifier_toolkit/model_validation/evaluator.py +1719 -0
  32. classifier_toolkit-0.5.1/classifier_toolkit/model_validation/model_assessment.py +975 -0
  33. classifier_toolkit-0.5.1/classifier_toolkit/risk_class/__init__.py +37 -0
  34. classifier_toolkit-0.5.1/classifier_toolkit/risk_class/risk_classes.py +1144 -0
  35. classifier_toolkit-0.5.1/classifier_toolkit/risk_class/risk_classes_dp.py +671 -0
  36. classifier_toolkit-0.5.1/examples/example_bayesian_search.ipynb +492 -0
  37. classifier_toolkit-0.5.1/examples/example_combination_feature_search.ipynb +537 -0
  38. classifier_toolkit-0.5.1/examples/example_explainability_catboost.ipynb +637 -0
  39. classifier_toolkit-0.5.1/examples/example_explainability_lgbm.ipynb +668 -0
  40. classifier_toolkit-0.5.1/examples/example_feature_reduction.ipynb +374 -0
  41. classifier_toolkit-0.5.1/examples/example_grid_search.ipynb +588 -0
  42. classifier_toolkit-0.5.1/examples/example_model_training_catboost.ipynb +194 -0
  43. classifier_toolkit-0.5.1/examples/example_model_training_lgbm.ipynb +186 -0
  44. classifier_toolkit-0.5.1/examples/example_model_validation.ipynb +369 -0
  45. classifier_toolkit-0.5.1/examples/example_recursive_feature_eliminator.ipynb +540 -0
  46. classifier_toolkit-0.5.1/examples/example_risk_classes_dp.ipynb +290 -0
  47. classifier_toolkit-0.5.1/examples/example_train_test_partition.ipynb +276 -0
  48. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/pyproject.toml +17 -2
  49. classifier_toolkit-0.5.1/tests/data_partition/test_split_train_test.py +247 -0
  50. classifier_toolkit-0.5.1/tests/datasets/test_demo_data.py +65 -0
  51. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_catboost_e2e.py +2 -3
  52. classifier_toolkit-0.5.1/tests/explainability/test_interactions.py +40 -0
  53. classifier_toolkit-0.5.1/tests/explainability/test_interactions_ranking.py +134 -0
  54. classifier_toolkit-0.5.1/tests/feature_reduction/test_correlation_missing.py +322 -0
  55. classifier_toolkit-0.5.1/tests/feature_reduction/test_correlation_tie_break.py +262 -0
  56. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_drift.py +112 -0
  57. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_reducer.py +118 -0
  58. classifier_toolkit-0.5.1/tests/feature_selection/test_combination_search.py +1151 -0
  59. classifier_toolkit-0.5.1/tests/feature_selection/test_recursive_feature_eliminator.py +1916 -0
  60. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_rfe.py +31 -15
  61. classifier_toolkit-0.5.1/tests/feature_selection/test_rfe_assessment.py +439 -0
  62. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_scoring.py +23 -13
  63. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/model_training/hyper_parameter_tuning/test_params.py +62 -0
  64. classifier_toolkit-0.5.1/tests/model_training/hyper_parameter_tuning/test_tuner.py +1492 -0
  65. classifier_toolkit-0.5.1/tests/model_validation/__init__.py +0 -0
  66. classifier_toolkit-0.5.1/tests/model_validation/test_compare_score_distributions.py +90 -0
  67. classifier_toolkit-0.5.1/tests/model_validation/test_evaluate_risk_classes_dp.py +46 -0
  68. classifier_toolkit-0.5.1/tests/model_validation/test_evaluator_multiclass.py +374 -0
  69. classifier_toolkit-0.5.1/tests/model_validation/test_evaluator_threshold.py +33 -0
  70. classifier_toolkit-0.5.1/tests/model_validation/test_model_assessment.py +760 -0
  71. classifier_toolkit-0.5.1/tests/model_validation/test_print_full_validation_report.py +101 -0
  72. classifier_toolkit-0.5.1/tests/model_validation/test_print_risk_class_validation_report.py +98 -0
  73. classifier_toolkit-0.5.1/tests/model_validation/test_score_distribution_psi.py +69 -0
  74. classifier_toolkit-0.5.1/tests/risk_class/__init__.py +0 -0
  75. classifier_toolkit-0.5.1/tests/risk_class/test_construct_bins_dp.py +281 -0
  76. classifier_toolkit-0.5.1/tests/risk_class/test_risk_classes.py +193 -0
  77. classifier_toolkit-0.5.1/tests/risk_class/test_validate_risk_classes.py +145 -0
  78. classifier_toolkit-0.3.6/.github/pull_request_template/default.md +0 -13
  79. classifier_toolkit-0.3.6/.github/workflows/checks.yaml +0 -148
  80. classifier_toolkit-0.3.6/.github/workflows/docs.yml +0 -31
  81. classifier_toolkit-0.3.6/.github/workflows/master.yaml +0 -48
  82. classifier_toolkit-0.3.6/.github/workflows/release.yaml +0 -51
  83. classifier_toolkit-0.3.6/.github/workflows/working-branch.yaml +0 -14
  84. classifier_toolkit-0.3.6/.python-version +0 -1
  85. classifier_toolkit-0.3.6/.sqlfluff +0 -38
  86. classifier_toolkit-0.3.6/Makefile +0 -22
  87. classifier_toolkit-0.3.6/classifier_toolkit/feature_selection/wrapper_methods/combination_search.py +0 -632
  88. classifier_toolkit-0.3.6/docs/CNAME +0 -1
  89. classifier_toolkit-0.3.6/docs/calibration/overview.md +0 -53
  90. classifier_toolkit-0.3.6/docs/changelog.md +0 -65
  91. classifier_toolkit-0.3.6/docs/data_partition/data_preprocess.md +0 -43
  92. classifier_toolkit-0.3.6/docs/data_partition/optimize_data.md +0 -30
  93. classifier_toolkit-0.3.6/docs/data_partition/overview.md +0 -30
  94. classifier_toolkit-0.3.6/docs/data_partition/split_train_test.md +0 -43
  95. classifier_toolkit-0.3.6/docs/eda/bivariate_analysis.md +0 -38
  96. classifier_toolkit-0.3.6/docs/eda/eda_toolkit.md +0 -65
  97. classifier_toolkit-0.3.6/docs/eda/feature_engineering.md +0 -60
  98. classifier_toolkit-0.3.6/docs/eda/first_glance.md +0 -54
  99. classifier_toolkit-0.3.6/docs/eda/overview.md +0 -128
  100. classifier_toolkit-0.3.6/docs/eda/univariate_analysis.md +0 -48
  101. classifier_toolkit-0.3.6/docs/eda/visualizations.md +0 -51
  102. classifier_toolkit-0.3.6/docs/eda/warnings/default_warnings.md +0 -45
  103. classifier_toolkit-0.3.6/docs/eda/warnings/warning_system.md +0 -32
  104. classifier_toolkit-0.3.6/docs/examples/eda_example.md +0 -71
  105. classifier_toolkit-0.3.6/docs/examples/feature_selection_advanced.md +0 -111
  106. classifier_toolkit-0.3.6/docs/examples/feature_selection_example.md +0 -123
  107. classifier_toolkit-0.3.6/docs/explainability/interactions.md +0 -48
  108. classifier_toolkit-0.3.6/docs/explainability/misclassification.md +0 -46
  109. classifier_toolkit-0.3.6/docs/explainability/overview.md +0 -87
  110. classifier_toolkit-0.3.6/docs/explainability/plots.md +0 -47
  111. classifier_toolkit-0.3.6/docs/explainability/toolkit.md +0 -59
  112. classifier_toolkit-0.3.6/docs/explainability/tree_explainer.md +0 -50
  113. classifier_toolkit-0.3.6/docs/feature_reduction/correlation.md +0 -34
  114. classifier_toolkit-0.3.6/docs/feature_reduction/counter_intuitive.md +0 -49
  115. classifier_toolkit-0.3.6/docs/feature_reduction/drift.md +0 -35
  116. classifier_toolkit-0.3.6/docs/feature_reduction/expert_rules.md +0 -26
  117. classifier_toolkit-0.3.6/docs/feature_reduction/low_variance.md +0 -22
  118. classifier_toolkit-0.3.6/docs/feature_reduction/overview.md +0 -49
  119. classifier_toolkit-0.3.6/docs/feature_reduction/predictive_power.md +0 -55
  120. classifier_toolkit-0.3.6/docs/feature_reduction/reducer.md +0 -46
  121. classifier_toolkit-0.3.6/docs/feature_selection/embedded_methods/elastic_net.md +0 -54
  122. classifier_toolkit-0.3.6/docs/feature_selection/feature_stability.md +0 -38
  123. classifier_toolkit-0.3.6/docs/feature_selection/meta_selector.md +0 -99
  124. classifier_toolkit-0.3.6/docs/feature_selection/overview.md +0 -89
  125. classifier_toolkit-0.3.6/docs/feature_selection/utils/data_handling.md +0 -60
  126. classifier_toolkit-0.3.6/docs/feature_selection/utils/scoring.md +0 -50
  127. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/bayesian_search.md +0 -44
  128. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/boruta.md +0 -49
  129. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/combination_search.md +0 -39
  130. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -35
  131. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/rfe.md +0 -90
  132. classifier_toolkit-0.3.6/docs/feature_selection/wrapper_methods/sequential_selection.md +0 -54
  133. classifier_toolkit-0.3.6/docs/index.md +0 -92
  134. classifier_toolkit-0.3.6/docs/model_training/overview.md +0 -51
  135. classifier_toolkit-0.3.6/docs/model_training/tuner.md +0 -359
  136. classifier_toolkit-0.3.6/docs/reference/calibration/ovr_calibration.md +0 -3
  137. classifier_toolkit-0.3.6/docs/reference/calibration/reliability.md +0 -3
  138. classifier_toolkit-0.3.6/docs/reference/data_partition/data_preprocess.md +0 -46
  139. classifier_toolkit-0.3.6/docs/reference/data_partition/optimize_data.md +0 -36
  140. classifier_toolkit-0.3.6/docs/reference/data_partition/overview.md +0 -37
  141. classifier_toolkit-0.3.6/docs/reference/data_partition/split_train_test.md +0 -57
  142. classifier_toolkit-0.3.6/docs/reference/eda/bivariate_analysis.md +0 -42
  143. classifier_toolkit-0.3.6/docs/reference/eda/eda_toolkit.md +0 -47
  144. classifier_toolkit-0.3.6/docs/reference/eda/feature_engineering.md +0 -42
  145. classifier_toolkit-0.3.6/docs/reference/eda/first_glance.md +0 -42
  146. classifier_toolkit-0.3.6/docs/reference/eda/overview.md +0 -35
  147. classifier_toolkit-0.3.6/docs/reference/eda/univariate_analysis.md +0 -43
  148. classifier_toolkit-0.3.6/docs/reference/eda/visualizations.md +0 -39
  149. classifier_toolkit-0.3.6/docs/reference/eda/warnings/default_warnings.md +0 -52
  150. classifier_toolkit-0.3.6/docs/reference/eda/warnings/warning_system.md +0 -36
  151. classifier_toolkit-0.3.6/docs/reference/explainability/interactions.md +0 -7
  152. classifier_toolkit-0.3.6/docs/reference/explainability/misclassification.md +0 -3
  153. classifier_toolkit-0.3.6/docs/reference/explainability/overview.md +0 -42
  154. classifier_toolkit-0.3.6/docs/reference/explainability/plots.md +0 -7
  155. classifier_toolkit-0.3.6/docs/reference/explainability/toolkit.md +0 -3
  156. classifier_toolkit-0.3.6/docs/reference/explainability/tree_explainer.md +0 -7
  157. classifier_toolkit-0.3.6/docs/reference/feature_reduction/base.md +0 -5
  158. classifier_toolkit-0.3.6/docs/reference/feature_reduction/correlation.md +0 -49
  159. classifier_toolkit-0.3.6/docs/reference/feature_reduction/counter_intuitive.md +0 -40
  160. classifier_toolkit-0.3.6/docs/reference/feature_reduction/drift.md +0 -75
  161. classifier_toolkit-0.3.6/docs/reference/feature_reduction/expert_rules.md +0 -16
  162. classifier_toolkit-0.3.6/docs/reference/feature_reduction/low_variance.md +0 -25
  163. classifier_toolkit-0.3.6/docs/reference/feature_reduction/overview.md +0 -33
  164. classifier_toolkit-0.3.6/docs/reference/feature_reduction/predictive_power.md +0 -68
  165. classifier_toolkit-0.3.6/docs/reference/feature_reduction/reducer.md +0 -121
  166. classifier_toolkit-0.3.6/docs/reference/feature_selection/base.md +0 -3
  167. classifier_toolkit-0.3.6/docs/reference/feature_selection/embedded_methods/elastic_net.md +0 -40
  168. classifier_toolkit-0.3.6/docs/reference/feature_selection/feature_stability.md +0 -38
  169. classifier_toolkit-0.3.6/docs/reference/feature_selection/meta_selector.md +0 -41
  170. classifier_toolkit-0.3.6/docs/reference/feature_selection/overview.md +0 -28
  171. classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/data_handling.md +0 -43
  172. classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/plottings.md +0 -5
  173. classifier_toolkit-0.3.6/docs/reference/feature_selection/utils/scoring.md +0 -37
  174. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/bayesian_search.md +0 -35
  175. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/boruta.md +0 -34
  176. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/combination_search.md +0 -111
  177. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/recursive_feature_eliminator.md +0 -268
  178. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/rfe.md +0 -62
  179. classifier_toolkit-0.3.6/docs/reference/feature_selection/wrapper_methods/sequential_selection.md +0 -55
  180. classifier_toolkit-0.3.6/docs/reference/model_training/params.md +0 -5
  181. classifier_toolkit-0.3.6/docs/reference/tuner/tuner.md +0 -3
  182. classifier_toolkit-0.3.6/examples/__init__.py +0 -1
  183. classifier_toolkit-0.3.6/examples/example_bayesian_search.ipynb +0 -4475
  184. classifier_toolkit-0.3.6/examples/example_combination_feature_search.ipynb +0 -4262
  185. classifier_toolkit-0.3.6/examples/example_explainability_catboost.ipynb +0 -1565
  186. classifier_toolkit-0.3.6/examples/example_explainability_lgbm.ipynb +0 -1625
  187. classifier_toolkit-0.3.6/examples/example_feature_reduction.ipynb +0 -2280
  188. classifier_toolkit-0.3.6/examples/example_grid_search.ipynb +0 -1975
  189. classifier_toolkit-0.3.6/examples/example_model_training_catboost.ipynb +0 -133
  190. classifier_toolkit-0.3.6/examples/example_model_training_lgbm.ipynb +0 -133
  191. classifier_toolkit-0.3.6/examples/example_recursive_feature_eliminator.ipynb +0 -862
  192. classifier_toolkit-0.3.6/examples/example_train_test_partition.ipynb +0 -446
  193. classifier_toolkit-0.3.6/main.py +0 -6
  194. classifier_toolkit-0.3.6/mkdocs.yml +0 -200
  195. classifier_toolkit-0.3.6/notebooks/paylater_removed.json +0 -244
  196. classifier_toolkit-0.3.6/ruff.toml +0 -46
  197. classifier_toolkit-0.3.6/tests/data_partition/test_split_train_test.py +0 -122
  198. classifier_toolkit-0.3.6/tests/feature_selection/test_combination_search.py +0 -403
  199. classifier_toolkit-0.3.6/tests/feature_selection/test_recursive_feature_eliminator.py +0 -638
  200. classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning/test_tuner.py +0 -418
  201. classifier_toolkit-0.3.6/uv.lock +0 -3998
  202. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/LICENSE +0 -0
  203. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/calibration/__init__.py +0 -0
  204. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/calibration/base.py +0 -0
  205. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/data_partition/__init__.py +0 -0
  206. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/data_partition/data_preprocess.py +0 -0
  207. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/data_partition/optimize_data.py +0 -0
  208. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/__init__.py +0 -0
  209. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/bivariate_analysis.py +0 -0
  210. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/feature_engineering.py +0 -0
  211. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/first_glance.py +0 -0
  212. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/univariate_analysis.py +0 -0
  213. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/warnings/__init__.py +0 -0
  214. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/warnings/automated_warnings.py +0 -0
  215. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/eda/warnings/default_warnings.py +0 -0
  216. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/__init__.py +0 -0
  217. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/base.py +0 -0
  218. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/expert_rules.py +0 -0
  219. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/low_variance.py +0 -0
  220. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_reduction/predictive_power.py +0 -0
  221. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/__init__.py +0 -0
  222. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/base.py +0 -0
  223. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/embedded_methods/__init__.py +0 -0
  224. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/embedded_methods/elastic_net.py +0 -0
  225. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/feature_stability.py +0 -0
  226. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/meta_selector.py +0 -0
  227. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/utils/__init__.py +0 -0
  228. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/utils/data_handling.py +0 -0
  229. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/utils/feature_type_constraints.py +0 -0
  230. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/utils/plottings.py +0 -0
  231. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/__init__.py +0 -0
  232. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/bayesian_search.py +0 -0
  233. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/boruta.py +0 -0
  234. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/rfe_catboost.py +0 -0
  235. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/feature_selection/wrapper_methods/sequential_selection.py +0 -0
  236. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/__init__.py +0 -0
  237. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/hyper_parameter_tuning/__init__.py +0 -0
  238. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/models/__init__.py +0 -0
  239. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/models/base.py +0 -0
  240. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/classifier_toolkit/model_training/utils/__init__.py +0 -0
  241. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/__init__.py +0 -0
  242. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/calibration/__init__.py +0 -0
  243. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/calibration/test_ovr_calibration.py +0 -0
  244. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/calibration/test_reliability.py +0 -0
  245. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/conftest.py +0 -0
  246. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/data_partition/__init__.py +0 -0
  247. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/data_partition/test_data_preprocess.py +0 -0
  248. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/data_partition/test_optimize_data.py +0 -0
  249. {classifier_toolkit-0.3.6/tests/eda → classifier_toolkit-0.5.1/tests/datasets}/__init__.py +0 -0
  250. {classifier_toolkit-0.3.6/tests/explainability → classifier_toolkit-0.5.1/tests/eda}/__init__.py +0 -0
  251. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_bivariate_analysis.py +0 -0
  252. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_feature_engineering.py +0 -0
  253. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_first_glance.py +0 -0
  254. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_univariate_analysis.py +0 -0
  255. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_visualizations.py +0 -0
  256. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/eda/test_warnings.py +0 -0
  257. {classifier_toolkit-0.3.6/tests/model_training → classifier_toolkit-0.5.1/tests/explainability}/__init__.py +0 -0
  258. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_misclassification.py +0 -0
  259. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_multiclass_e2e.py +0 -0
  260. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_plots.py +0 -0
  261. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_smoke.py +0 -0
  262. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_toolkit.py +0 -0
  263. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/explainability/test_tree_explainer.py +0 -0
  264. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/__init__.py +0 -0
  265. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_correlation.py +0 -0
  266. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_counter_intuitive.py +0 -0
  267. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_expert_rules.py +0 -0
  268. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_low_variance.py +0 -0
  269. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_predictive_power.py +0 -0
  270. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_reduction/test_smoke.py +0 -0
  271. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/__init__.py +0 -0
  272. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_bayesian_search.py +0 -0
  273. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_boruta.py +0 -0
  274. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_elastic_net.py +0 -0
  275. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_feature_stability.py +0 -0
  276. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_rfe_catboost.py +0 -0
  277. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/feature_selection/test_sequential_selection.py +0 -0
  278. {classifier_toolkit-0.3.6/tests/model_training/hyper_parameter_tuning → classifier_toolkit-0.5.1/tests/model_training}/__init__.py +0 -0
  279. {classifier_toolkit-0.3.6/tests/model_training/models → classifier_toolkit-0.5.1/tests/model_training/hyper_parameter_tuning}/__init__.py +0 -0
  280. /classifier_toolkit-0.3.6/docs/stylesheets/extra.css → /classifier_toolkit-0.5.1/tests/model_training/models/__init__.py +0 -0
  281. {classifier_toolkit-0.3.6 → classifier_toolkit-0.5.1}/tests/model_training/models/test_ensemble_methods.py +0 -0
@@ -178,4 +178,8 @@ cython_debug/
178
178
  catboost_info/
179
179
 
180
180
  # Gitkeep
181
- !/**/.gitkeep
181
+ !/**/.gitkeep
182
+
183
+ # Claude Code local state (worktrees, personal settings)
184
+ .claude/worktrees/
185
+ .claude/settings.local.json
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: classifier-toolkit
3
- Version: 0.3.6
3
+ Version: 0.5.1
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.9
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 tasks in the finance domain, specifically for default and fraud labeling. It includes several packages designed to address the main steps in any machine learning/data science task:
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 `EDA_Toolkit`. Provides EDA and feature engineering functionality with all necessary visualizations.
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. Evaluation and reporting: To be implemented.
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
- tuner = Tuner(model_name="lightgbm", metric="auc", search_type="bayesian", n_trials=50)
145
- tuner.fit(X_train, y_train, X_val, y_val, X_test=X_test, y_test=y_test)
168
+ ```python
169
+ from classifier_toolkit.risk_class import RiskClassBuilderDP
146
170
 
147
- best_model = tuner.best_model
148
- tuner.results_df # full trial results
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
- Custom parameter search spaces can be defined via `ModelParams` and `ParamRange`.
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**: Tests are split into two groups (`eda` and `feature_selection`) that run simultaneously, reducing test time by ~50%
166
- - **Shared Caching**: Both parallel jobs share the same dependency cache (~1.7GB), avoiding duplicate downloads
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
- * Developing comprehensive evaluation and reporting tools to assist with model assessment.
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 tasks in the finance domain, specifically for default and fraud labeling. It includes several packages designed to address the main steps in any machine learning/data science task:
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 `EDA_Toolkit`. Provides EDA and feature engineering functionality with all necessary visualizations.
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. Evaluation and reporting: To be implemented.
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
- tuner = Tuner(model_name="lightgbm", metric="auc", search_type="bayesian", n_trials=50)
114
- tuner.fit(X_train, y_train, X_val, y_val, X_test=X_test, y_test=y_test)
136
+ ```python
137
+ from classifier_toolkit.risk_class import RiskClassBuilderDP
115
138
 
116
- best_model = tuner.best_model
117
- tuner.results_df # full trial results
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
- Custom parameter search spaces can be defined via `ModelParams` and `ParamRange`.
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**: Tests are split into two groups (`eda` and `feature_selection`) that run simultaneously, reducing test time by ~50%
135
- - **Shared Caching**: Both parallel jobs share the same dependency cache (~1.7GB), avoiding duplicate downloads
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
- * Developing comprehensive evaluation and reporting tools to assist with model assessment.
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.
@@ -0,0 +1,6 @@
1
+ """Type aliases shared across the toolkit.""" # noqa: INP001
2
+
3
+ from typing import Union
4
+
5
+ #: A class label as found in ``y`` and ``model.classes_`` (e.g. ``pos_label``).
6
+ ClassLabel = Union[str, int]
@@ -14,10 +14,9 @@ from typing import Dict, Optional, Sequence, Union
14
14
 
15
15
  import numpy as np
16
16
 
17
+ from classifier_toolkit._typing import ClassLabel
17
18
  from classifier_toolkit.calibration.base import CalibrationError
18
19
 
19
- ClassLabel = Union[str, int]
20
-
21
20
 
22
21
  class OVRHistogramCalibrator:
23
22
  """Calibrate multiclass probabilities via One-vs-Rest histogram binning.
@@ -13,7 +13,7 @@ import matplotlib.pyplot as plt
13
13
  import numpy as np
14
14
  from sklearn.calibration import calibration_curve
15
15
 
16
- ClassLabel = Union[str, int]
16
+ from classifier_toolkit._typing import ClassLabel
17
17
 
18
18
 
19
19
  def plot_reliability_curves(
@@ -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 based on the most recent organizations.
15
- Takes the most recent organizations (by first observation date) for the test set
16
- based on the specified test_size proportion, and the remaining organizations for training.
17
- Iteratively adjusts the split to maintain default rate balance within tolerance.
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
- Proportion of organizations to include in test set (most recent ones)
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 acceptable difference in default rates between train and test (5%)
27
- max_iterations : int, default=50
28
- Maximum number of iterations to find a balanced split
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 labels
38
+ Column containing the binary (0/1) target
31
39
  org_id_col : str, default='org_id'
32
- Column containing organization IDs
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) - Training and testing dataframes
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
- # Get the earliest observation date for each organization
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, ascending=True)
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
- n_test_orgs = int(total_orgs * test_size)
57
-
58
- print("=== RECENT ORGANIZATIONS SPLIT WITH RATE TOLERANCE ===")
59
- print(f"Test size target: {test_size:.1%}")
60
- print(f"Rate tolerance: {rate_tolerance:.1%}")
61
- print(f"Total organizations: {total_orgs}")
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
- # Try different splits around the target to find one within tolerance
64
- best_split = None
65
- best_rate_diff = float("inf")
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
- # Search range: ±30% of target test size
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
- min_test_orgs = max(1, n_test_orgs - search_range)
70
- max_test_orgs = min(total_orgs - 1, n_test_orgs + search_range)
71
-
72
- print(
73
- f"Searching for balanced split (testing {min_test_orgs} to {max_test_orgs} orgs)..."
74
- )
75
-
76
- for test_org_count in range(min_test_orgs, max_test_orgs + 1):
77
- # Take organizations for this test size
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
- # Calculate default rates
88
- train_rate = temp_train[label_col].mean()
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"✓ Found balanced split at {test_org_count} test orgs (rate diff: {rate_diff:.4f})"
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
- if best_split is None:
112
- # Fallback to original target
113
- best_split = {
114
- "test_orgs_data": org_first_dates.tail(n_test_orgs),
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
- print("\nDate ranges:")
181
- print(
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
- f"Testing all observations: {test_df[date_col].min().strftime('%Y-%m-%d')} to {test_df[date_col].max().strftime('%Y-%m-%d')}"
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(
@@ -0,0 +1,3 @@
1
+ from ._demo import ID_COLS, TARGET_COL, make_demo_data
2
+
3
+ __all__ = ["ID_COLS", "TARGET_COL", "make_demo_data"]