classifier-toolkit 0.1.0__py3-none-any.whl

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 (26) hide show
  1. classifier_toolkit/eda/__init__.py +19 -0
  2. classifier_toolkit/eda/bivariate_analysis.py +413 -0
  3. classifier_toolkit/eda/eda_toolkit.py +549 -0
  4. classifier_toolkit/eda/feature_engineering.py +1310 -0
  5. classifier_toolkit/eda/first_glance.py +253 -0
  6. classifier_toolkit/eda/univariate_analysis.py +778 -0
  7. classifier_toolkit/eda/visualizations.py +1248 -0
  8. classifier_toolkit/eda/warnings/__init__.py +4 -0
  9. classifier_toolkit/eda/warnings/automated_warnings.py +20 -0
  10. classifier_toolkit/eda/warnings/default_warnings.py +286 -0
  11. classifier_toolkit/feature_selection/__init__.py +33 -0
  12. classifier_toolkit/feature_selection/base.py +182 -0
  13. classifier_toolkit/feature_selection/embedded_methods/__init__.py +7 -0
  14. classifier_toolkit/feature_selection/embedded_methods/elastic_net.py +178 -0
  15. classifier_toolkit/feature_selection/meta_selector.py +329 -0
  16. classifier_toolkit/feature_selection/utils/__init__.py +17 -0
  17. classifier_toolkit/feature_selection/utils/plottings.py +65 -0
  18. classifier_toolkit/feature_selection/utils/scoring.py +86 -0
  19. classifier_toolkit/feature_selection/wrapper_methods/__init__.py +11 -0
  20. classifier_toolkit/feature_selection/wrapper_methods/rfe.py +345 -0
  21. classifier_toolkit/feature_selection/wrapper_methods/sequential_selection.py +566 -0
  22. classifier_toolkit/model_fitting/__init__.py +0 -0
  23. classifier_toolkit/model_fitting/model_search.py +3 -0
  24. classifier_toolkit-0.1.0.dist-info/METADATA +99 -0
  25. classifier_toolkit-0.1.0.dist-info/RECORD +26 -0
  26. classifier_toolkit-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,566 @@
1
+ from typing import Dict, List, Literal, Optional, Set, Union
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from lightgbm import LGBMClassifier
6
+ from sklearn.ensemble import RandomForestClassifier
7
+ from sklearn.linear_model import LogisticRegression
8
+ from sklearn.metrics import get_scorer
9
+ from sklearn.model_selection import cross_val_score, train_test_split
10
+ from xgboost import XGBClassifier
11
+
12
+ from classifier_toolkit.feature_selection.base import (
13
+ BaseFeatureSelector,
14
+ FeatureSelectionError,
15
+ )
16
+
17
+
18
+ class SequentialSelector(BaseFeatureSelector):
19
+ """
20
+ Sequential feature selector using various estimators.
21
+
22
+ This class implements forward, backward, and bidirectional feature selection
23
+ using different estimators.
24
+
25
+ Parameters
26
+ ----------
27
+ estimator_params : Optional[Dict[str, float]]
28
+ Parameters for the estimator.
29
+ estimator_name : {'random_forest', 'lightgbm', 'xgboost', 'logistic_regression'}, optional
30
+ The name of the estimator to use, by default 'random_forest'.
31
+ n_features_to_select : int, optional
32
+ The number of features to select, by default 1.
33
+ scoring : {'accuracy', 'f1', 'precision', 'recall', 'roc_auc'}, optional
34
+ The scoring metric to use, by default 'roc_auc'.
35
+ cv : int, optional
36
+ The number of cross-validation folds, by default 5.
37
+ method : {'forward', 'backward', 'bidirectional'}, optional
38
+ The selection method to use, by default 'forward'.
39
+ verbose : int, optional
40
+ Verbosity level, by default 0.
41
+ tolerance : float, optional
42
+ Tolerance for early stopping, by default 1e-4.
43
+ n_jobs : int, optional
44
+ The number of jobs to run in parallel, by default -1.
45
+ early_stopping_rounds : int, optional
46
+ The number of rounds for early stopping, by default 5.
47
+
48
+ Attributes
49
+ ----------
50
+ estimator_params : Dict[str, float]
51
+ Parameters for the estimator.
52
+ method : str
53
+ The selection method used.
54
+ feature_scores_ : Dict[str, float]
55
+ Scores for each feature.
56
+ tolerance : float
57
+ Tolerance for early stopping.
58
+ n_jobs : int
59
+ The number of jobs to run in parallel.
60
+ early_stopping_rounds : int
61
+ The number of rounds for early stopping.
62
+ estimator_name : str
63
+ The name of the estimator used.
64
+ estimator : object
65
+ The estimator object.
66
+ """
67
+
68
+ def __init__(
69
+ self,
70
+ estimator_params: Optional[Dict[str, Union[int, float, str]]],
71
+ estimator_name: Literal[
72
+ "random_forest", "lightgbm", "xgboost", "logistic_regression"
73
+ ] = "random_forest",
74
+ n_features_to_select: int = 1,
75
+ scoring: Literal[
76
+ "accuracy", "f1", "precision", "recall", "roc_auc"
77
+ ] = "roc_auc",
78
+ cv: int = 5,
79
+ method: Literal["forward", "backward", "bidirectional"] = "forward",
80
+ verbose: int = 0,
81
+ tolerance: float = 1e-4,
82
+ n_jobs: int = -1,
83
+ early_stopping_rounds: int = 5,
84
+ ) -> None:
85
+ super().__init__(
86
+ estimator=None,
87
+ n_features_to_select=n_features_to_select,
88
+ scoring=scoring,
89
+ cv=cv,
90
+ verbose=verbose,
91
+ )
92
+ self.estimator_params = estimator_params or {}
93
+ self.method = method
94
+ self.feature_scores_: Dict[str, float] = {}
95
+ self.tolerance = tolerance
96
+ self.n_jobs = n_jobs
97
+ self.early_stopping_rounds = early_stopping_rounds
98
+ self.estimator_name = estimator_name
99
+ self.estimator = self.initialize_estimator() # type: ignore
100
+
101
+ # Handle the scoring parameter
102
+ self.scorer = get_scorer(scoring)
103
+
104
+ def initialize_estimator(self):
105
+ """
106
+ Initialize the estimator based on the provided name and parameters.
107
+
108
+ Returns
109
+ -------
110
+ object
111
+ The initialized estimator.
112
+
113
+ Raises
114
+ ------
115
+ ValueError
116
+ If the estimator name is not recognized.
117
+ """
118
+ if self.estimator_name == "random_forest":
119
+ return RandomForestClassifier(**self.estimator_params)
120
+ elif self.estimator_name == "lightgbm":
121
+ return LGBMClassifier(**self.estimator_params)
122
+ elif self.estimator_name == "xgboost":
123
+ return XGBClassifier(**self.estimator_params)
124
+ elif self.estimator_name == "logistic_regression":
125
+ return LogisticRegression(**self.estimator_params)
126
+ else:
127
+ raise ValueError(
128
+ "Estimator must be 'random_forest', 'lightgbm', 'xgboost', or 'logistic_regression'"
129
+ )
130
+
131
+ def fit(self, X: pd.DataFrame, y: pd.Series) -> "SequentialSelector":
132
+ """
133
+ Fit the SequentialSelector to the data.
134
+
135
+ Parameters
136
+ ----------
137
+ X : pd.DataFrame
138
+ The input features.
139
+ y : pd.Series
140
+ The target variable.
141
+
142
+ Returns
143
+ -------
144
+ SequentialSelector
145
+ The fitted SequentialSelector instance.
146
+
147
+ Raises
148
+ ------
149
+ ValueError
150
+ If the selection method is not recognized.
151
+ """
152
+ self.feature_names_ = X.columns.tolist()
153
+
154
+ if self.method == "forward":
155
+ self._forward_selection(X, y)
156
+ elif self.method == "backward":
157
+ self._backward_selection(X, y)
158
+ elif self.method == "bidirectional":
159
+ self._bidirectional_selection(X, y)
160
+ else:
161
+ raise ValueError("Method must be 'forward', 'backward', or 'bidirectional'")
162
+
163
+ self.feature_importances_ = self.get_feature_importances()
164
+ return self
165
+
166
+ def _get_score(self, X: pd.DataFrame, y: pd.Series, features: List[int]) -> float:
167
+ """
168
+ Calculate the cross-validation score for a subset of features.
169
+
170
+ Parameters
171
+ ----------
172
+ X : pd.DataFrame
173
+ The input features.
174
+ y : pd.Series
175
+ The target variable.
176
+ features : List[int]
177
+ The indices of features to use.
178
+
179
+ Returns
180
+ -------
181
+ float
182
+ The mean cross-validation score.
183
+
184
+ Raises
185
+ ------
186
+ ValueError
187
+ If the estimator is not set.
188
+ """
189
+ X_subset = X.iloc[:, features]
190
+
191
+ if self.estimator is not None:
192
+ scores = cross_val_score(
193
+ self.estimator, X_subset, y, scoring=self.scorer, cv=self.cv, n_jobs=-1
194
+ )
195
+ return float(np.mean(scores))
196
+ else:
197
+ raise ValueError("Estimator is not set.")
198
+
199
+ def _get_score_fast(self, X_train, X_val, y_train, y_val, features: List[int]):
200
+ """
201
+ Calculate the score for a subset of features using a fast method.
202
+
203
+ Parameters
204
+ ----------
205
+ X_train : pd.DataFrame
206
+ The training input features.
207
+ X_val : pd.DataFrame
208
+ The validation input features.
209
+ y_train : pd.Series
210
+ The training target variable.
211
+ y_val : pd.Series
212
+ The validation target variable.
213
+ features : List[int]
214
+ The indices of features to use.
215
+
216
+ Returns
217
+ -------
218
+ float
219
+ The score for the given features.
220
+
221
+ Raises
222
+ ------
223
+ ValueError
224
+ If the estimator is not set.
225
+ """
226
+ X_train_subset = X_train.iloc[:, features]
227
+ X_val_subset = X_val.iloc[:, features]
228
+
229
+ if self.estimator is not None:
230
+ self.estimator.fit(X_train_subset, y_train) # type: ignore
231
+ return self.scorer(self.estimator, X_val_subset, y_val)
232
+ else:
233
+ raise ValueError("Estimator is not set.")
234
+
235
+ def _forward_selection(self, X: pd.DataFrame, y: pd.Series) -> None:
236
+ """
237
+ Perform forward feature selection.
238
+
239
+ Parameters
240
+ ----------
241
+ X : pd.DataFrame
242
+ The input features.
243
+ y : pd.Series
244
+ The target variable.
245
+ """
246
+ selected: List[int] = []
247
+ remaining = list(range(X.shape[1]))
248
+ feature_scores: Dict[int, float] = {}
249
+
250
+ X_train, X_val, y_train, y_val = train_test_split(
251
+ X, y, test_size=0.2, random_state=42
252
+ )
253
+
254
+ max_features = (
255
+ self.n_features_to_select
256
+ if self.n_features_to_select is not None
257
+ else X.shape[1]
258
+ )
259
+
260
+ while len(selected) < max_features:
261
+ scores = []
262
+ for feature in remaining:
263
+ temp_selected = [*selected, feature]
264
+ score = self._get_score_fast(
265
+ X_train, X_val, y_train, y_val, temp_selected
266
+ )
267
+ scores.append((score, feature))
268
+
269
+ best_score, best_feature = max(scores)
270
+ selected.append(best_feature)
271
+ remaining.remove(best_feature)
272
+ feature_scores[best_feature] = best_score
273
+
274
+ print(
275
+ f"Selected feature: {X.columns[best_feature]}, Score: {best_score:.6f}"
276
+ )
277
+
278
+ if self.n_features_to_select is None and len(selected) == X.shape[1]:
279
+ break
280
+
281
+ self.selected_features_ = [X.columns[i] for i in selected]
282
+ self.feature_scores_ = {X.columns[k]: v for k, v in feature_scores.items()}
283
+
284
+ def _backward_selection(self, X: pd.DataFrame, y: pd.Series) -> None:
285
+ """
286
+ Perform backward feature selection.
287
+
288
+ Parameters
289
+ ----------
290
+ X : pd.DataFrame
291
+ The input features.
292
+ y : pd.Series
293
+ The target variable.
294
+ """
295
+ selected = list(range(X.shape[1]))
296
+ feature_scores: Dict[int, float] = {
297
+ feature: 0.0 for feature in selected
298
+ } # Initialize with floats
299
+
300
+ X_train, X_val, y_train, y_val = train_test_split(
301
+ X, y, test_size=0.2, random_state=42
302
+ )
303
+
304
+ min_features = (
305
+ self.n_features_to_select if self.n_features_to_select is not None else 1
306
+ )
307
+
308
+ while len(selected) > min_features:
309
+ scores = []
310
+ for feature in selected:
311
+ temp_selected = [f for f in selected if f != feature]
312
+ score = self._get_score_fast(
313
+ X_train, X_val, y_train, y_val, temp_selected
314
+ )
315
+ scores.append((score, feature))
316
+
317
+ best_score, worst_feature = max(scores)
318
+ selected.remove(worst_feature)
319
+ feature_scores[worst_feature] = best_score
320
+
321
+ print(
322
+ f"Removed feature: {X.columns[worst_feature]}, Score: {best_score:.6f}"
323
+ )
324
+
325
+ if self.n_features_to_select is None and len(selected) == 1:
326
+ break
327
+
328
+ self.selected_features_ = [X.columns[i] for i in selected]
329
+ self.feature_scores_ = {X.columns[k]: v for k, v in feature_scores.items()}
330
+
331
+ def _bidirectional_selection(self, X: pd.DataFrame, y: pd.Series) -> None:
332
+ """
333
+ Perform bidirectional feature selection.
334
+
335
+ Parameters
336
+ ----------
337
+ X : pd.DataFrame
338
+ The input features.
339
+ y : pd.Series
340
+ The target variable.
341
+ """
342
+ selected: List[int] = []
343
+ remaining: List[int] = list(range(X.shape[1]))
344
+ feature_scores: Dict[int, List[float]] = {
345
+ feature: [] for feature in range(X.shape[1])
346
+ }
347
+ recently_added: Set[int] = set()
348
+ recently_removed: Set[int] = set()
349
+
350
+ X_train, X_val, y_train, y_val = train_test_split(
351
+ X, y, test_size=0.2, random_state=42
352
+ )
353
+
354
+ # Start with the best single feature
355
+ initial_scores = [
356
+ (self._get_score_fast(X_train, X_val, y_train, y_val, [f]), f)
357
+ for f in remaining
358
+ ]
359
+ best_score, best_feature = max(initial_scores)
360
+ selected.append(best_feature)
361
+ remaining.remove(best_feature)
362
+ feature_scores[best_feature].append(best_score)
363
+ recently_added.add(best_feature)
364
+
365
+ print(f"Initial feature: {X.columns[best_feature]}, Score: {best_score:.6f}")
366
+
367
+ max_iterations = (
368
+ X.shape[1] * 2
369
+ if self.n_features_to_select is None
370
+ else self.n_features_to_select * 2
371
+ )
372
+ iteration = 0
373
+
374
+ while iteration < max_iterations:
375
+ iteration += 1
376
+ # Forward step
377
+ forward_scores = [
378
+ (
379
+ self._get_score_fast(
380
+ X_train,
381
+ X_val,
382
+ y_train,
383
+ y_val,
384
+ [*selected, f],
385
+ ),
386
+ f,
387
+ )
388
+ for f in remaining
389
+ if f not in recently_removed
390
+ ]
391
+ best_forward_score, best_forward_feature = (
392
+ max(forward_scores) if forward_scores else (-np.inf, None)
393
+ )
394
+
395
+ # Backward step (if there's more than one feature)
396
+ backward_scores = []
397
+ if len(selected) > 1:
398
+ backward_scores = [
399
+ (
400
+ self._get_score_fast(
401
+ X_train,
402
+ X_val,
403
+ y_train,
404
+ y_val,
405
+ [f for f in selected if f != feat],
406
+ ),
407
+ feat,
408
+ )
409
+ for feat in selected
410
+ if feat not in recently_added
411
+ ]
412
+ best_backward_score, best_backward_feature = (
413
+ max(backward_scores) if backward_scores else (-np.inf, None)
414
+ )
415
+
416
+ # Update feature scores
417
+ for score, feature in forward_scores:
418
+ feature_scores[feature].append(score)
419
+ for score, feature in backward_scores:
420
+ feature_scores[feature].append(score)
421
+
422
+ # Decide whether to add or remove a feature
423
+ if (
424
+ best_forward_score > best_backward_score
425
+ and best_forward_feature is not None
426
+ ):
427
+ selected.append(best_forward_feature)
428
+ remaining.remove(best_forward_feature)
429
+ recently_added.add(best_forward_feature)
430
+ recently_removed.clear()
431
+ print(
432
+ f"Added feature: {X.columns[best_forward_feature]}, Score: {best_forward_score:.6f}"
433
+ )
434
+ elif best_backward_feature is not None:
435
+ selected.remove(best_backward_feature)
436
+ remaining.append(best_backward_feature)
437
+ recently_removed.add(best_backward_feature)
438
+ recently_added.clear()
439
+ print(
440
+ f"Removed feature: {X.columns[best_backward_feature]}, Score: {best_backward_score:.6f}"
441
+ )
442
+ else:
443
+ print("No improvement possible. Stopping.")
444
+ break
445
+
446
+ # Clear recent sets after a few iterations to allow reconsideration
447
+ if len(selected) % 5 == 0:
448
+ recently_added.clear()
449
+ recently_removed.clear()
450
+
451
+ print(f"Iteration {iteration}, Selected features: {len(selected)}")
452
+
453
+ # Check if we've reached the desired number of features
454
+ if len(selected) == self.n_features_to_select:
455
+ print(
456
+ f"Reached desired number of features ({self.n_features_to_select}). Stopping."
457
+ )
458
+ break
459
+
460
+ # Check if we've reached the maximum number of iterations
461
+ if iteration >= max_iterations:
462
+ print(
463
+ f"Reached maximum number of iterations ({max_iterations}). Stopping."
464
+ )
465
+ break
466
+
467
+ self.selected_features_ = [
468
+ X.columns[i] for i in selected[: self.n_features_to_select]
469
+ ]
470
+
471
+ # Calculate average scores for all features
472
+ if self.feature_scores_ is None:
473
+ self.feature_scores_ = {}
474
+
475
+ for feature_idx, scores in feature_scores.items():
476
+ feature_name = X.columns[feature_idx]
477
+ self.feature_scores_[feature_name] = (
478
+ float(np.mean(scores)) if scores else 0.0
479
+ )
480
+
481
+ print("\nFeature selection completed.")
482
+ print(f"Total iterations: {iteration}")
483
+ print(f"Selected features: {len(self.selected_features_)}")
484
+ print("Feature importances (average scores):")
485
+ for feature, score in sorted( # type: ignore
486
+ self.feature_scores_.items(), key=lambda x: x[1], reverse=True
487
+ ):
488
+ print(f"{feature}: {score:.6f}")
489
+
490
+ def get_feature_importances(self) -> pd.Series:
491
+ """
492
+ Get the feature importances (scores) from the fitted model.
493
+
494
+ Returns
495
+ -------
496
+ pd.Series
497
+ The feature importances.
498
+
499
+ Raises
500
+ ------
501
+ FeatureSelectionError
502
+ If the selector has not been fitted yet.
503
+ """
504
+ if self.feature_scores_ is None:
505
+ raise FeatureSelectionError(
506
+ "Selector has not been fitted yet. Call 'fit' first."
507
+ )
508
+
509
+ importances = pd.Series(self.feature_scores_)
510
+
511
+ # Normalize importances
512
+ if importances.sum() > 0:
513
+ importances = importances / importances.sum()
514
+ else:
515
+ print("Warning: Sum of importances is zero. Skipping normalization.")
516
+
517
+ return importances
518
+
519
+ def transform(self, X: pd.DataFrame) -> pd.DataFrame:
520
+ """
521
+ Transform the input data by selecting the chosen features.
522
+
523
+ Parameters
524
+ ----------
525
+ X : pd.DataFrame
526
+ The input features.
527
+
528
+ Returns
529
+ -------
530
+ pd.DataFrame
531
+ The transformed data containing only the selected features.
532
+
533
+ Raises
534
+ ------
535
+ FeatureSelectionError
536
+ If the selector has not been fitted yet.
537
+ """
538
+ if self.selected_features_ is None:
539
+ raise FeatureSelectionError(
540
+ "Selector has not been fitted yet. Call 'fit' first."
541
+ )
542
+ return X[self.selected_features_]
543
+
544
+ def print_feature_importances(self):
545
+ """
546
+ Print the feature importances (scores) in descending order.
547
+
548
+ Raises
549
+ ------
550
+ FeatureSelectionError
551
+ If feature importances are not available (i.e., fit hasn't been called).
552
+ """
553
+ if self.feature_importances_ is None:
554
+ raise FeatureSelectionError(
555
+ "Feature importances are not available. Call 'fit' first."
556
+ )
557
+
558
+ sorted_importances = sorted(
559
+ zip(self.feature_importances_.index, self.feature_importances_),
560
+ key=lambda x: x[1],
561
+ reverse=True,
562
+ )
563
+
564
+ print("Feature importances (in descending order):")
565
+ for feature, importance in sorted_importances:
566
+ print(f"('{feature}', {importance:.6f})")
File without changes
@@ -0,0 +1,3 @@
1
+ """
2
+ import optuna
3
+ """
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.1
2
+ Name: classifier-toolkit
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: gauthier.marquand
6
+ Author-email: gauthier.marquand@qonto.com
7
+ Requires-Python: >=3.9,<3.11
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Requires-Dist: catboost (>=1.2.2,<2.0.0)
12
+ Requires-Dist: category-encoders (>=2.6.3,<3.0.0)
13
+ Requires-Dist: colorama (>=0.4.6,<0.5.0)
14
+ Requires-Dist: graphviz (>=0.20.3,<0.21.0)
15
+ Requires-Dist: ipywidgets (>=8.1.5,<9.0.0)
16
+ Requires-Dist: lightgbm (>=4.5.0,<5.0.0)
17
+ Requires-Dist: matplotlib (>=3.9.2,<4.0.0)
18
+ Requires-Dist: nbformat (>=5.10.4,<6.0.0)
19
+ Requires-Dist: numpy (<1.26)
20
+ Requires-Dist: optuna (>=3.5.0,<4.0.0)
21
+ Requires-Dist: pandas (>=2.2.0,<3.0.0)
22
+ Requires-Dist: polars (>=1.2.1,<2.0.0)
23
+ Requires-Dist: pyarrow (>=17.0.0,<18.0.0)
24
+ Requires-Dist: pydantic-settings (>=2.3.4,<3.0.0)
25
+ Requires-Dist: pydot (>=3.0.1,<4.0.0)
26
+ Requires-Dist: pylint (>=3.2.6,<4.0.0)
27
+ Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
28
+ Requires-Dist: scipy (<1.12)
29
+ Requires-Dist: seaborn (>=0.10.1)
30
+ Requires-Dist: shap (>=0.44.1,<0.45.0)
31
+ Requires-Dist: snowflake (>=0.10.0,<0.11.0)
32
+ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
33
+ Requires-Dist: xgboost (>=2.1.1,<3.0.0)
34
+ Requires-Dist: ydata-profiling (>=4.6.4,<5.0.0)
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Classifier Toolkit
38
+
39
+ [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
40
+ [![Linting - Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
41
+ [![Code style - Black](https://img.shields.io/badge/Code%20Style-Black-000000.svg)](https://github.com/psf/black)
42
+
43
+ This is a new project.
44
+
45
+ -----
46
+
47
+ ## Table of Content
48
+
49
+ <!-- [[_TOC_]] -->
50
+
51
+ 1. [Installation](#installation)
52
+ 2. [Usage](#usage)
53
+ 3. [Modules Overview](#modules-overview)
54
+ 4. [Future Work](#future-work)
55
+
56
+ ### Installation
57
+
58
+ This library is published in the PyPI directory. To install, users can run pip install 'classifier_toolkit' command.
59
+
60
+ ### Usage
61
+
62
+ 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:
63
+
64
+ 1. EDA: which is accessible by EDA_Toolkit. This package provides the EDA and feature engineering functionality alongside with all the necessary visualizations.
65
+ 2. Feature Selection: To be implemented.
66
+ 3. Model fitting and hyperparameter tuning: To be implemented.
67
+ 4. Evaluation and reporting: To be implemented.
68
+
69
+ In the future, the package architectures will be included here. However, for now please consult the docstrings in the specific methods in the relevant modules.
70
+
71
+ **Note**: that this library does not contain data wrangling steps (although it contains feature engineering), it's an intermediate step between EDA and feature engineering where users should fix any data quality related issues. Therefore, conducting the EDA is crucial to mitigate any issues before moving onto the feature engineering and the subsequent steps.
72
+
73
+ ### Modules Overview
74
+
75
+ - **EDA Toolkit**: This module includes classes and methods for performing comprehensive exploratory data analysis. It provides automated warnings for data quality issues, univariate and bivariate analysis, and various data visualizations to help understand the dataset.
76
+
77
+ - **Univariate Analysis**: This class focuses on the analysis of individual variables. It includes methods for calculating statistical measures, visualizing distributions, and assessing relationships between variables and a target through techniques like Cramer's V and Information Value. This helps in understanding the significance and distribution of each feature independently.
78
+
79
+ - **Bivariate Analysis**: This class deals with the analysis of two variables to understand their relationship. It includes functionalities for generating correlation heatmaps, performing ANOVA tests between numerical and categorical variables, and computing pairwise Cramer's V for categorical features. This aids in identifying patterns and correlations between pairs of variables, which is crucial for feature selection and engineering.
80
+
81
+ - **Feature Engineering**: This module assists in transforming features, handling missing values, encoding categorical variables, and more. It aims to enhance the dataset's quality for better model performance.
82
+
83
+ - **Visualizations**: This module offers a wide range of plotting capabilities to visually analyze data distributions, relationships, and other crucial aspects of the dataset.
84
+
85
+ - **Automated Warnings**: A utility to automatically check the dataset for common issues such as missing or duplicate values, outliers, and more, providing warnings to guide data cleaning efforts.
86
+
87
+ - **Feature Selection**: This module provides various feature selection techniques:
88
+ - **Embedded Methods**: Includes ElasticNet for regularization-based feature selection.
89
+ - **Wrapper Methods**:
90
+ - Recursive Feature Elimination (RFE) with support for various ensemble methods (Random Forest, XGBoost, LightGBM, CatBoost).
91
+ - Sequential Feature Selection (forward, backward, floating, and bidirectional).
92
+ - **Meta Selector**: Combines multiple feature selection methods to provide a robust selection.
93
+ - **Utility Functions**: Includes scoring functions and plotting utilities for feature importance visualization.
94
+
95
+ ### Future Work
96
+ The next planned improvements and additions to the library include:
97
+ * Adding model fitting and hyperparameter tuning functionalities.
98
+ * Developing comprehensive evaluation and reporting tools to assist with model assessment.
99
+ * Expanding documentation to include architecture diagrams and detailed usage examples.