classifier-toolkit 0.1.2__tar.gz → 0.1.4__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.1.2 → classifier_toolkit-0.1.4}/PKG-INFO +1 -1
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/eda_toolkit.py +18 -10
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/feature_engineering.py +9 -48
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/first_glance.py +1 -1
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/univariate_analysis.py +107 -92
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/visualizations.py +27 -70
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/pyproject.toml +1 -1
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/README.md +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/bivariate_analysis.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/warnings/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/warnings/automated_warnings.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/warnings/default_warnings.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/base.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/embedded_methods/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/embedded_methods/elastic_net.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/meta_selector.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/utils/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/utils/plottings.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/utils/scoring.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/wrapper_methods/__init__.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/wrapper_methods/rfe.py +0 -0
- {classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/wrapper_methods/sequential_selection.py +0 -0
|
@@ -4,8 +4,6 @@ from typing import Any, Dict, List, Literal, Optional, Union
|
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
|
|
7
|
-
from examples.constants import PATH_DATA_PROCESSED
|
|
8
|
-
|
|
9
7
|
from .bivariate_analysis import BivariateAnalysis
|
|
10
8
|
from .feature_engineering import FeatureEngineering
|
|
11
9
|
from .first_glance import FirstGlance
|
|
@@ -44,6 +42,7 @@ class EDAToolkit:
|
|
|
44
42
|
self,
|
|
45
43
|
dataframe: pd.DataFrame,
|
|
46
44
|
can_be_negative: List[str],
|
|
45
|
+
path_data_folder: Path,
|
|
47
46
|
target_column: Optional[str] = None,
|
|
48
47
|
exclusion: Optional[List[str]] = None,
|
|
49
48
|
numerical_columns: Optional[List[str]] = None,
|
|
@@ -84,6 +83,7 @@ class EDAToolkit:
|
|
|
84
83
|
self.categorical_columns = categorical_columns or []
|
|
85
84
|
self.id_column = id_column or ""
|
|
86
85
|
self.to_be_enc = to_be_enc or []
|
|
86
|
+
self.path_data_folder = path_data_folder
|
|
87
87
|
|
|
88
88
|
# Initialize an empty list for transformations
|
|
89
89
|
self.transformations: TransformationType = []
|
|
@@ -206,12 +206,20 @@ class EDAToolkit:
|
|
|
206
206
|
self.first_glance.super_vision()
|
|
207
207
|
self.first_glance.check_duplicates()
|
|
208
208
|
|
|
209
|
-
def plot_target_evolution(self):
|
|
209
|
+
def plot_target_evolution(self, time_column: str, evolving_numeric: str):
|
|
210
210
|
"""
|
|
211
211
|
Plot the target balance and evolution over time.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
time_column : str
|
|
216
|
+
The name of the time column.
|
|
217
|
+
evolving_numeric : str
|
|
218
|
+
The name of the numerical column to plot that we want to see the evolution of
|
|
219
|
+
which helps us understanding the behavior of the target column.
|
|
212
220
|
"""
|
|
213
221
|
self.visualizations.plot_target_balance()
|
|
214
|
-
self.visualizations.plot_target_evolution(
|
|
222
|
+
self.visualizations.plot_target_evolution(time_column, evolving_numeric)
|
|
215
223
|
|
|
216
224
|
def plot_numerical_distributions(self, sub_plots: bool = False):
|
|
217
225
|
"""
|
|
@@ -232,7 +240,7 @@ class EDAToolkit:
|
|
|
232
240
|
"""
|
|
233
241
|
self.visualizations.plot_categorical_value_counts()
|
|
234
242
|
self.visualizations.visualize_high_cardinality(
|
|
235
|
-
|
|
243
|
+
excluded_columns=self.exclusion, id_column=self.id_column
|
|
236
244
|
)
|
|
237
245
|
self.visualizations.visualize_low_cardinality()
|
|
238
246
|
|
|
@@ -377,7 +385,7 @@ class EDAToolkit:
|
|
|
377
385
|
"""
|
|
378
386
|
_, filtered_cramers = self.univariate_analysis.plot_cramers_v(
|
|
379
387
|
self.numerical_columns,
|
|
380
|
-
|
|
388
|
+
excluded_columns=self.exclusion,
|
|
381
389
|
filter_threshold=threshold_c,
|
|
382
390
|
)
|
|
383
391
|
|
|
@@ -406,7 +414,7 @@ class EDAToolkit:
|
|
|
406
414
|
imputed = self.feature_engineering.handle_missing_values(imputation_method)
|
|
407
415
|
transforms = self.get_transformations(unwanted_features=eliminated)
|
|
408
416
|
|
|
409
|
-
EDAToolkit.save_intermediary(
|
|
417
|
+
EDAToolkit.save_intermediary(self.path_data_folder, imputed, "imputed")
|
|
410
418
|
print("Imputed dataframe saved in the processed directory.")
|
|
411
419
|
|
|
412
420
|
self.feature_engineering = FeatureEngineering(
|
|
@@ -432,7 +440,7 @@ class EDAToolkit:
|
|
|
432
440
|
to_transformed
|
|
433
441
|
)
|
|
434
442
|
transforms = self.get_transformations()
|
|
435
|
-
EDAToolkit.save_intermediary(
|
|
443
|
+
EDAToolkit.save_intermediary(self.path_data_folder, transformed, "transformed")
|
|
436
444
|
print("Transformed dataframe saved in the processed directory.")
|
|
437
445
|
|
|
438
446
|
self.feature_engineering = FeatureEngineering(
|
|
@@ -458,7 +466,7 @@ class EDAToolkit:
|
|
|
458
466
|
Method to use for handling low cardinality columns.
|
|
459
467
|
"""
|
|
460
468
|
binned = self.feature_engineering.binnings(methods=handling_method)
|
|
461
|
-
EDAToolkit.save_intermediary(
|
|
469
|
+
EDAToolkit.save_intermediary(self.path_data_folder, binned, "binned")
|
|
462
470
|
print(
|
|
463
471
|
"Variables with low cardinality are treated and saved in the processed directory."
|
|
464
472
|
)
|
|
@@ -485,7 +493,7 @@ class EDAToolkit:
|
|
|
485
493
|
)
|
|
486
494
|
if high_card is not None:
|
|
487
495
|
EDAToolkit.save_intermediary(
|
|
488
|
-
|
|
496
|
+
self.path_data_folder, high_card, "high_cardinality_treated"
|
|
489
497
|
)
|
|
490
498
|
print(
|
|
491
499
|
"High cardinality variables are treated and dataframe saved in the processed directory."
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/feature_engineering.py
RENAMED
|
@@ -364,9 +364,11 @@ class FeatureEngineering:
|
|
|
364
364
|
raise ValueError(f"Column {column} not found in transformed data")
|
|
365
365
|
|
|
366
366
|
self.data = updated_data
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
|
|
368
|
+
for transform in self.transformations:
|
|
369
|
+
if transform["method"] == "normality_transform":
|
|
370
|
+
transform["selected_columns"] = columns_to_keep
|
|
371
|
+
|
|
370
372
|
return self.data
|
|
371
373
|
|
|
372
374
|
def handle_high_cardinality(
|
|
@@ -990,7 +992,10 @@ class FeatureEngineering:
|
|
|
990
992
|
|
|
991
993
|
self.data = data
|
|
992
994
|
self.data.info()
|
|
993
|
-
self._log_transformation(
|
|
995
|
+
self._log_transformation(
|
|
996
|
+
"encoding_categorical",
|
|
997
|
+
{"method": method, "selected_columns": self.encode_list},
|
|
998
|
+
)
|
|
994
999
|
return self.data
|
|
995
1000
|
|
|
996
1001
|
####### FEATURE ENGINEERING: OPTIONAL FUNCTIONS #######
|
|
@@ -1264,47 +1269,3 @@ class FeatureEngineering:
|
|
|
1264
1269
|
return self.data
|
|
1265
1270
|
|
|
1266
1271
|
percentile_capping = apply_winsorization
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
'''
|
|
1270
|
-
def apply_winsorization(
|
|
1271
|
-
self, selected_columns: List[str], percentile: float = 0.05
|
|
1272
|
-
) -> pd.DataFrame:
|
|
1273
|
-
"""
|
|
1274
|
-
Apply winsorization to numerical columns to limit extreme values.
|
|
1275
|
-
|
|
1276
|
-
Parameters
|
|
1277
|
-
----------
|
|
1278
|
-
selected_columns : List[str]
|
|
1279
|
-
List of columns to apply winsorization to.
|
|
1280
|
-
percentile : float, optional
|
|
1281
|
-
The percentage of data to be considered as extreme values on each side, by default 0.05.
|
|
1282
|
-
|
|
1283
|
-
Returns
|
|
1284
|
-
-------
|
|
1285
|
-
pd.DataFrame
|
|
1286
|
-
DataFrame with winsorized columns.
|
|
1287
|
-
"""
|
|
1288
|
-
if len(selected_columns) == 0:
|
|
1289
|
-
selected_columns = self.numerical_columns
|
|
1290
|
-
|
|
1291
|
-
for column in selected_columns:
|
|
1292
|
-
if column == self.target_column:
|
|
1293
|
-
print(f"{column} is the target column. Skipping winsorization.")
|
|
1294
|
-
continue
|
|
1295
|
-
|
|
1296
|
-
lower_bound = np.percentile(self.data[column], percentile * 100)
|
|
1297
|
-
upper_bound = np.percentile(self.data[column], (1 - percentile) * 100)
|
|
1298
|
-
self.data[column] = np.clip(self.data[column], lower_bound, upper_bound)
|
|
1299
|
-
|
|
1300
|
-
print(f"\nWinsorization applied with {percentile * 100}% capping on each side.")
|
|
1301
|
-
print(self.data[selected_columns].describe())
|
|
1302
|
-
|
|
1303
|
-
self._log_transformation(
|
|
1304
|
-
"winsorization",
|
|
1305
|
-
{"selected_columns": selected_columns, "percentile": percentile},
|
|
1306
|
-
)
|
|
1307
|
-
return self.data
|
|
1308
|
-
|
|
1309
|
-
percentile_capping = apply_winsorization
|
|
1310
|
-
'''
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/first_glance.py
RENAMED
|
@@ -112,7 +112,7 @@ values in more detail, please call the see_duplicates method
|
|
|
112
112
|
top_n : int, optional
|
|
113
113
|
Number of top values to display, by default 10.
|
|
114
114
|
"""
|
|
115
|
-
for col in self.
|
|
115
|
+
for col in self.categorical_columns:
|
|
116
116
|
print(Fore.GREEN + f"\nColumn: {col}")
|
|
117
117
|
value_counts = self.data[col].value_counts().head(top_n)
|
|
118
118
|
for value, count in value_counts.items():
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/univariate_analysis.py
RENAMED
|
@@ -31,13 +31,13 @@ class UnivariateAnalysis:
|
|
|
31
31
|
self.numerical_features = numerical_features or []
|
|
32
32
|
|
|
33
33
|
@staticmethod
|
|
34
|
-
def _get_cramers_v(
|
|
34
|
+
def _get_cramers_v(df: pd.DataFrame, var1: str, var2: str) -> float:
|
|
35
35
|
"""
|
|
36
36
|
Calculate Cramer's V statistic for two variables.
|
|
37
37
|
|
|
38
38
|
Parameters
|
|
39
39
|
----------
|
|
40
|
-
|
|
40
|
+
df : pd.DataFrame
|
|
41
41
|
The data containing the variables.
|
|
42
42
|
var1 : str
|
|
43
43
|
The first variable.
|
|
@@ -49,15 +49,15 @@ class UnivariateAnalysis:
|
|
|
49
49
|
float
|
|
50
50
|
Cramer's V statistic.
|
|
51
51
|
"""
|
|
52
|
-
confusion_matrix = pd.crosstab(
|
|
52
|
+
confusion_matrix = pd.crosstab(df[var1], df[var2])
|
|
53
53
|
chi2 = chi2_contingency(confusion_matrix)[0]
|
|
54
54
|
n = confusion_matrix.sum().sum()
|
|
55
55
|
min_dim = min(confusion_matrix.shape) - 1
|
|
56
56
|
|
|
57
57
|
return np.sqrt(chi2 / (n * min_dim))
|
|
58
58
|
|
|
59
|
-
def
|
|
60
|
-
self, numerical_features: List[str],
|
|
59
|
+
def _prepare_cramers_v_features(
|
|
60
|
+
self, numerical_features: List[str], num_bins: int = 5
|
|
61
61
|
) -> List[str]:
|
|
62
62
|
"""
|
|
63
63
|
Prepare features for Cramer's V calculation by binning numerical features.
|
|
@@ -66,7 +66,7 @@ class UnivariateAnalysis:
|
|
|
66
66
|
----------
|
|
67
67
|
numerical_features : List[str]
|
|
68
68
|
List of numerical feature names.
|
|
69
|
-
|
|
69
|
+
num_bins : int, optional
|
|
70
70
|
Number of bins for continuous variables, by default 5.
|
|
71
71
|
|
|
72
72
|
Returns
|
|
@@ -74,13 +74,13 @@ class UnivariateAnalysis:
|
|
|
74
74
|
List[str]
|
|
75
75
|
List of features prepared for Cramer's V calculation.
|
|
76
76
|
"""
|
|
77
|
-
|
|
77
|
+
cramers_v_var_list = self.data.select_dtypes(
|
|
78
78
|
include=["object", "category"]
|
|
79
79
|
).columns.tolist()
|
|
80
80
|
|
|
81
81
|
# Exclude the target column
|
|
82
|
-
|
|
83
|
-
var for var in
|
|
82
|
+
cramers_v_var_list = [
|
|
83
|
+
var for var in cramers_v_var_list if var != self.target_column
|
|
84
84
|
]
|
|
85
85
|
|
|
86
86
|
for num in numerical_features:
|
|
@@ -91,12 +91,12 @@ class UnivariateAnalysis:
|
|
|
91
91
|
): # Ensure there are at least two unique values for binning
|
|
92
92
|
try:
|
|
93
93
|
self.data[f"{num}_bin"] = pd.qcut(
|
|
94
|
-
self.data[num], q=
|
|
94
|
+
self.data[num], q=num_bins, duplicates="drop"
|
|
95
95
|
)
|
|
96
96
|
# Check if the resulting bins are more than 1
|
|
97
97
|
if self.data[f"{num}_bin"].nunique() <= 1:
|
|
98
98
|
raise ValueError(
|
|
99
|
-
f"Only 1 bin created for {num} with q={
|
|
99
|
+
f"Only 1 bin created for {num} with q={num_bins}."
|
|
100
100
|
)
|
|
101
101
|
|
|
102
102
|
except ValueError as e:
|
|
@@ -113,19 +113,19 @@ class UnivariateAnalysis:
|
|
|
113
113
|
self.data[f"{num}_bin"] = pd.qcut(
|
|
114
114
|
self.data[num], q=2, duplicates="drop"
|
|
115
115
|
)
|
|
116
|
-
|
|
116
|
+
cramers_v_var_list.append(f"{num}_bin")
|
|
117
117
|
else:
|
|
118
118
|
# Handle the case where there is only one unique value
|
|
119
119
|
print(f"Skipping {num} as it has only {unique_values} unique value(s).")
|
|
120
120
|
|
|
121
|
-
return
|
|
121
|
+
return cramers_v_var_list
|
|
122
122
|
|
|
123
123
|
def plot_cramers_v(
|
|
124
124
|
self,
|
|
125
125
|
numerical_features: List[str],
|
|
126
|
-
|
|
126
|
+
excluded_columns: List[str],
|
|
127
127
|
filter_threshold: float,
|
|
128
|
-
|
|
128
|
+
num_bins: int = 5,
|
|
129
129
|
fig_width: int = 800,
|
|
130
130
|
fig_height: int = 800,
|
|
131
131
|
) -> Tuple[pd.DataFrame, List[str]]:
|
|
@@ -136,9 +136,9 @@ class UnivariateAnalysis:
|
|
|
136
136
|
----------
|
|
137
137
|
numerical_features : List[str]
|
|
138
138
|
List of numerical feature names.
|
|
139
|
-
|
|
139
|
+
excluded_columns : List[str]
|
|
140
140
|
List of variables to exclude from the analysis.
|
|
141
|
-
|
|
141
|
+
num_bins : int, optional
|
|
142
142
|
Number of bins for continuous variables, by default 5.
|
|
143
143
|
fig_width : int, optional
|
|
144
144
|
Width of the figure in pixels, by default 800.
|
|
@@ -150,22 +150,24 @@ class UnivariateAnalysis:
|
|
|
150
150
|
pd.DataFrame
|
|
151
151
|
DataFrame containing Cramer's V values.
|
|
152
152
|
"""
|
|
153
|
-
|
|
153
|
+
cramers_v_var_list = self._prepare_cramers_v_features(
|
|
154
|
+
numerical_features, num_bins
|
|
155
|
+
)
|
|
154
156
|
|
|
155
157
|
# Exclude any specified variables
|
|
156
|
-
|
|
157
|
-
var for var in
|
|
158
|
+
cramers_v_var_list = [
|
|
159
|
+
var for var in cramers_v_var_list if var not in excluded_columns
|
|
158
160
|
]
|
|
159
161
|
|
|
160
162
|
rows = []
|
|
161
|
-
for cat in
|
|
163
|
+
for cat in cramers_v_var_list:
|
|
162
164
|
cramers = UnivariateAnalysis._get_cramers_v(
|
|
163
165
|
self.data, cat, self.target_column
|
|
164
166
|
)
|
|
165
167
|
rows.append(round(cramers, 2))
|
|
166
168
|
|
|
167
169
|
cramers_results = pd.DataFrame(
|
|
168
|
-
rows, columns=[self.target_column], index=
|
|
170
|
+
rows, columns=[self.target_column], index=cramers_v_var_list
|
|
169
171
|
)
|
|
170
172
|
|
|
171
173
|
# Create a Plotly heatmap
|
|
@@ -194,18 +196,22 @@ class UnivariateAnalysis:
|
|
|
194
196
|
return cramers_results, filtered_vars
|
|
195
197
|
|
|
196
198
|
def _calculate_information_value(
|
|
197
|
-
self,
|
|
199
|
+
self,
|
|
200
|
+
feature_column: str,
|
|
201
|
+
target_column: str,
|
|
202
|
+
num_bins: int = 10,
|
|
203
|
+
show_woe: bool = False,
|
|
198
204
|
) -> Union[Tuple[float, pd.DataFrame], float]:
|
|
199
205
|
"""
|
|
200
206
|
Calculate Information Value for a single feature.
|
|
201
207
|
|
|
202
208
|
Parameters
|
|
203
209
|
----------
|
|
204
|
-
|
|
210
|
+
feature_column : str
|
|
205
211
|
Name of the feature column.
|
|
206
|
-
|
|
212
|
+
target_column : str
|
|
207
213
|
Name of the target column.
|
|
208
|
-
|
|
214
|
+
num_bins : int, optional
|
|
209
215
|
Number of bins for continuous variables, by default 10.
|
|
210
216
|
show_woe : bool, optional
|
|
211
217
|
Boolean to show WOE values, by default False.
|
|
@@ -217,21 +223,23 @@ class UnivariateAnalysis:
|
|
|
217
223
|
"""
|
|
218
224
|
df = pd.DataFrame(
|
|
219
225
|
{
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
feature_column: self.data[feature_column],
|
|
227
|
+
target_column: self.data[target_column].astype(float),
|
|
222
228
|
}
|
|
223
229
|
)
|
|
224
230
|
|
|
225
|
-
if df[
|
|
226
|
-
df["bins"] = pd.qcut(df[
|
|
231
|
+
if df[feature_column].dtype in ["int64", "float64"]:
|
|
232
|
+
df["bins"] = pd.qcut(df[feature_column], q=num_bins, duplicates="drop")
|
|
227
233
|
else:
|
|
228
|
-
df["bins"] = df[
|
|
234
|
+
df["bins"] = df[feature_column]
|
|
229
235
|
|
|
230
|
-
total_good = df[
|
|
231
|
-
total_bad = df[
|
|
236
|
+
total_good = df[target_column].sum()
|
|
237
|
+
total_bad = df[target_column].count() - total_good
|
|
232
238
|
|
|
233
239
|
# Explicitly setting observed=False to retain current behavior
|
|
234
|
-
grouped = df.groupby("bins", observed=False)[
|
|
240
|
+
grouped = df.groupby("bins", observed=False)[target_column].agg(
|
|
241
|
+
["sum", "count"]
|
|
242
|
+
)
|
|
235
243
|
grouped["good"] = grouped["sum"]
|
|
236
244
|
grouped["bad"] = grouped["count"] - grouped["sum"]
|
|
237
245
|
|
|
@@ -255,7 +263,7 @@ class UnivariateAnalysis:
|
|
|
255
263
|
numerical_features: List[str],
|
|
256
264
|
filter_threshold: float,
|
|
257
265
|
target_column: str,
|
|
258
|
-
|
|
266
|
+
num_bins: int = 10,
|
|
259
267
|
fig_width: int = 800,
|
|
260
268
|
fig_height: int = 800,
|
|
261
269
|
) -> Tuple[pd.DataFrame, List[str]]:
|
|
@@ -268,7 +276,7 @@ class UnivariateAnalysis:
|
|
|
268
276
|
List of numerical feature names.
|
|
269
277
|
target_column : str
|
|
270
278
|
Name of the target column.
|
|
271
|
-
|
|
279
|
+
num_bins : int, optional
|
|
272
280
|
Number of bins for continuous variables, by default 10.
|
|
273
281
|
fig_width : int, optional
|
|
274
282
|
Width of the figure in pixels, by default 800.
|
|
@@ -282,7 +290,7 @@ class UnivariateAnalysis:
|
|
|
282
290
|
"""
|
|
283
291
|
iv_values = []
|
|
284
292
|
for feature in numerical_features:
|
|
285
|
-
iv = self._calculate_information_value(feature, target_column,
|
|
293
|
+
iv = self._calculate_information_value(feature, target_column, num_bins)
|
|
286
294
|
iv_values.append(iv)
|
|
287
295
|
|
|
288
296
|
iv_df = pd.DataFrame(
|
|
@@ -412,7 +420,7 @@ class UnivariateAnalysis:
|
|
|
412
420
|
|
|
413
421
|
fig.show()
|
|
414
422
|
|
|
415
|
-
def _make_partitions(self,
|
|
423
|
+
def _make_partitions(self, num_partitions: int) -> pd.DataFrame:
|
|
416
424
|
"""
|
|
417
425
|
Partition the numerical features into 4 bins.
|
|
418
426
|
|
|
@@ -425,21 +433,21 @@ class UnivariateAnalysis:
|
|
|
425
433
|
for num in self.numerical_features:
|
|
426
434
|
partitioned[num + "_bin"] = pd.qcut(
|
|
427
435
|
x=partitioned[num],
|
|
428
|
-
q=
|
|
436
|
+
q=num_partitions,
|
|
429
437
|
labels=False,
|
|
430
438
|
duplicates="drop",
|
|
431
439
|
).astype("category")
|
|
432
440
|
return partitioned
|
|
433
441
|
|
|
434
442
|
def get_num_feature_repartition(
|
|
435
|
-
self,
|
|
443
|
+
self, time_column: str, num_partitions: int = 4, freq: str = "1ME"
|
|
436
444
|
) -> Optional[pd.DataFrame]:
|
|
437
445
|
"""
|
|
438
446
|
Plot the risk class repartition through time and return a table of the risk class repartition through time.
|
|
439
447
|
|
|
440
448
|
Parameters
|
|
441
449
|
----------
|
|
442
|
-
|
|
450
|
+
time_column : str
|
|
443
451
|
Name of the column that contains the observation date.
|
|
444
452
|
freq : str, optional
|
|
445
453
|
The frequency at which the risk class is aggregated ('D', 'M', or 'Y'), by default '1ME'.
|
|
@@ -449,17 +457,17 @@ class UnivariateAnalysis:
|
|
|
449
457
|
Optional[pd.DataFrame]
|
|
450
458
|
DataFrame containing the risk class repartition through time.
|
|
451
459
|
"""
|
|
452
|
-
partitioned = self._make_partitions(
|
|
460
|
+
partitioned = self._make_partitions(num_partitions)
|
|
453
461
|
|
|
454
462
|
# Drop rows where the time column is NaT
|
|
455
|
-
if partitioned[
|
|
463
|
+
if partitioned[time_column].isnull().any():
|
|
456
464
|
print(
|
|
457
|
-
f"There are missing entries in the {
|
|
465
|
+
f"There are missing entries in the {time_column} column, dropping them for the functionality; however, try to mitigate the problem."
|
|
458
466
|
)
|
|
459
|
-
partitioned = partitioned.dropna(subset=[
|
|
467
|
+
partitioned = partitioned.dropna(subset=[time_column])
|
|
460
468
|
|
|
461
469
|
row_nb = math.ceil(len(self.numerical_features) / 2)
|
|
462
|
-
fig, ax = plt.subplots(row_nb, 2, figsize=(20,
|
|
470
|
+
fig, ax = plt.subplots(row_nb, 2, figsize=(20, num_partitions * row_nb))
|
|
463
471
|
i, j = 0, 0
|
|
464
472
|
|
|
465
473
|
for num in self.numerical_features:
|
|
@@ -468,14 +476,15 @@ class UnivariateAnalysis:
|
|
|
468
476
|
# Group by and count
|
|
469
477
|
draw = (
|
|
470
478
|
partitioned.groupby(
|
|
471
|
-
[num + "_bin", pd.Grouper(key=
|
|
479
|
+
[num + "_bin", pd.Grouper(key=time_column, freq=freq)],
|
|
480
|
+
observed=False,
|
|
472
481
|
)[self.target_column]
|
|
473
482
|
.count()
|
|
474
483
|
.reset_index()
|
|
475
484
|
)
|
|
476
485
|
|
|
477
486
|
# Create 'freq' column with aligned indices
|
|
478
|
-
draw["freq"] = draw.groupby([
|
|
487
|
+
draw["freq"] = draw.groupby([time_column])[self.target_column].transform(
|
|
479
488
|
lambda x: x / x.sum()
|
|
480
489
|
)
|
|
481
490
|
|
|
@@ -483,7 +492,7 @@ class UnivariateAnalysis:
|
|
|
483
492
|
draw_pivot = pd.pivot_table(
|
|
484
493
|
draw,
|
|
485
494
|
values="freq",
|
|
486
|
-
index=
|
|
495
|
+
index=time_column,
|
|
487
496
|
columns=num + "_bin",
|
|
488
497
|
observed=False,
|
|
489
498
|
)
|
|
@@ -501,8 +510,8 @@ class UnivariateAnalysis:
|
|
|
501
510
|
|
|
502
511
|
def _prepare_data_for_psi(
|
|
503
512
|
self,
|
|
504
|
-
|
|
505
|
-
|
|
513
|
+
num_partitions: int,
|
|
514
|
+
time_column: str,
|
|
506
515
|
start_date: Union[str, datetime, date],
|
|
507
516
|
end_date: Union[str, datetime, date],
|
|
508
517
|
):
|
|
@@ -511,14 +520,14 @@ class UnivariateAnalysis:
|
|
|
511
520
|
|
|
512
521
|
Parameters
|
|
513
522
|
----------
|
|
514
|
-
|
|
523
|
+
time_column : str
|
|
515
524
|
Name of the column that contains the observation date.
|
|
516
525
|
start_date : Union[str, datetime, date]
|
|
517
526
|
Start date for the PSI calculation.
|
|
518
527
|
end_date : Union[str, datetime, date]
|
|
519
528
|
End date for the PSI calculation.
|
|
520
529
|
"""
|
|
521
|
-
self.data = self._make_partitions(
|
|
530
|
+
self.data = self._make_partitions(num_partitions)
|
|
522
531
|
|
|
523
532
|
# Convert string dates to datetime if necessary
|
|
524
533
|
if isinstance(start_date, str):
|
|
@@ -526,21 +535,21 @@ class UnivariateAnalysis:
|
|
|
526
535
|
if isinstance(end_date, str):
|
|
527
536
|
end_date = pd.to_datetime(end_date)
|
|
528
537
|
|
|
529
|
-
# Ensure
|
|
530
|
-
self.data[
|
|
538
|
+
# Ensure time_column is in datetime format
|
|
539
|
+
self.data[time_column] = pd.to_datetime(self.data[time_column])
|
|
531
540
|
|
|
532
|
-
_filter_date = (self.data[
|
|
533
|
-
self.data[
|
|
541
|
+
_filter_date = (self.data[time_column] >= start_date) & (
|
|
542
|
+
self.data[time_column] < end_date
|
|
534
543
|
)
|
|
535
544
|
self.data = self.data.loc[_filter_date]
|
|
536
545
|
self.data.reset_index(drop=True, inplace=True)
|
|
537
546
|
|
|
538
547
|
def _calculate_psi_single(
|
|
539
548
|
self,
|
|
540
|
-
|
|
549
|
+
time_column: str,
|
|
541
550
|
time_expected: Union[str, datetime, date],
|
|
542
|
-
|
|
543
|
-
|
|
551
|
+
column: str,
|
|
552
|
+
num_buckets: int,
|
|
544
553
|
bucket_type: Literal["quantile", "fixed_width"] = "quantile",
|
|
545
554
|
):
|
|
546
555
|
"""
|
|
@@ -548,13 +557,13 @@ class UnivariateAnalysis:
|
|
|
548
557
|
|
|
549
558
|
Parameters
|
|
550
559
|
----------
|
|
551
|
-
|
|
560
|
+
time_column : str
|
|
552
561
|
Name of the column that contains the observation date.
|
|
553
562
|
time_expected : Union[str, datetime, date]
|
|
554
563
|
The expected date for the PSI calculation.
|
|
555
|
-
|
|
564
|
+
column : str
|
|
556
565
|
Name of the column to calculate the PSI.
|
|
557
|
-
|
|
566
|
+
num_buckets : int
|
|
558
567
|
Number of buckets for binning.
|
|
559
568
|
bucket_type : Literal["quantile", "fixed_width"]
|
|
560
569
|
The type of binning to use.
|
|
@@ -567,11 +576,11 @@ class UnivariateAnalysis:
|
|
|
567
576
|
if isinstance(time_expected, str):
|
|
568
577
|
time_expected = pd.to_datetime(time_expected)
|
|
569
578
|
|
|
570
|
-
_filter_expected = self.data[
|
|
571
|
-
expected = self.data.loc[_filter_expected,
|
|
572
|
-
observed = self.data.loc[~_filter_expected,
|
|
579
|
+
_filter_expected = self.data[time_column] < time_expected
|
|
580
|
+
expected = self.data.loc[_filter_expected, column]
|
|
581
|
+
observed = self.data.loc[~_filter_expected, column]
|
|
573
582
|
|
|
574
|
-
bins = self._create_bins(self.data[
|
|
583
|
+
bins = self._create_bins(self.data[column], num_buckets, bucket_type)
|
|
575
584
|
|
|
576
585
|
expected_counts, _ = np.histogram(expected, bins=bins)
|
|
577
586
|
observed_counts, _ = np.histogram(observed, bins=bins)
|
|
@@ -591,13 +600,13 @@ class UnivariateAnalysis:
|
|
|
591
600
|
def _create_bins(
|
|
592
601
|
self,
|
|
593
602
|
series: pd.Series,
|
|
594
|
-
|
|
603
|
+
num_buckets: int,
|
|
595
604
|
bucket_type: Literal["quantile", "fixed_width"],
|
|
596
605
|
) -> np.ndarray:
|
|
597
606
|
if bucket_type == "quantile":
|
|
598
|
-
return pd.qcut(series, q=
|
|
607
|
+
return pd.qcut(series, q=num_buckets, duplicates="drop", retbins=True)[1]
|
|
599
608
|
else: # fixed_width
|
|
600
|
-
return pd.cut(series, bins=
|
|
609
|
+
return pd.cut(series, bins=num_buckets, retbins=True)[1]
|
|
601
610
|
|
|
602
611
|
def _create_buckets(self, series: pd.Series, bins: np.ndarray) -> pd.Series:
|
|
603
612
|
return pd.cut(
|
|
@@ -633,25 +642,25 @@ class UnivariateAnalysis:
|
|
|
633
642
|
|
|
634
643
|
def calculate_psi(
|
|
635
644
|
self,
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
645
|
+
train_df: pd.DataFrame,
|
|
646
|
+
test_df: Optional[pd.DataFrame],
|
|
647
|
+
time_column: str,
|
|
639
648
|
time_expected: Union[str, datetime, date],
|
|
640
|
-
|
|
649
|
+
num_buckets: int = 10,
|
|
641
650
|
bucket_type: Literal["quantile", "fixed_width"] = "quantile",
|
|
642
651
|
epsilon: float = 1e-5,
|
|
643
652
|
) -> pd.DataFrame:
|
|
644
653
|
psi_values = {}
|
|
645
654
|
for feature in self.numerical_features:
|
|
646
|
-
if
|
|
647
|
-
expected =
|
|
648
|
-
observed =
|
|
655
|
+
if test_df is None:
|
|
656
|
+
expected = train_df[train_df[time_column] < time_expected][feature]
|
|
657
|
+
observed = train_df[train_df[time_column] >= time_expected][feature]
|
|
649
658
|
else:
|
|
650
|
-
expected =
|
|
651
|
-
observed =
|
|
659
|
+
expected = train_df[feature]
|
|
660
|
+
observed = test_df[feature]
|
|
652
661
|
|
|
653
662
|
combined = pd.concat([expected, observed])
|
|
654
|
-
bins = self._create_bins(combined,
|
|
663
|
+
bins = self._create_bins(combined, num_buckets, bucket_type)
|
|
655
664
|
psi = self._calculate_psi(expected, observed, bins, epsilon)
|
|
656
665
|
psi_values[feature] = psi
|
|
657
666
|
|
|
@@ -698,12 +707,12 @@ class UnivariateAnalysis:
|
|
|
698
707
|
|
|
699
708
|
def compute_psi(
|
|
700
709
|
self,
|
|
701
|
-
|
|
710
|
+
time_column: str,
|
|
702
711
|
time_expected: Union[str, datetime, date],
|
|
703
712
|
start_date: Union[str, datetime, date],
|
|
704
713
|
end_date: Union[str, datetime, date],
|
|
705
714
|
test_data: Optional[pd.DataFrame] = None,
|
|
706
|
-
|
|
715
|
+
num_buckets: int = 10,
|
|
707
716
|
bucket_type: Literal["quantile", "fixed_width"] = "quantile",
|
|
708
717
|
test_mode: bool = False,
|
|
709
718
|
) -> pd.DataFrame:
|
|
@@ -714,21 +723,27 @@ class UnivariateAnalysis:
|
|
|
714
723
|
if isinstance(time_expected, str):
|
|
715
724
|
time_expected = pd.to_datetime(time_expected)
|
|
716
725
|
|
|
717
|
-
self.data[
|
|
726
|
+
self.data[time_column] = pd.to_datetime(self.data[time_column])
|
|
718
727
|
filtered_data = self.data[
|
|
719
|
-
(self.data[
|
|
728
|
+
(self.data[time_column] >= start_date) & (self.data[time_column] < end_date)
|
|
720
729
|
]
|
|
721
730
|
|
|
722
731
|
if test_data is not None:
|
|
723
|
-
test_data[
|
|
732
|
+
test_data[time_column] = pd.to_datetime(test_data[time_column])
|
|
724
733
|
test_filtered = test_data[
|
|
725
|
-
(test_data[
|
|
734
|
+
(test_data[time_column] >= start_date)
|
|
735
|
+
& (test_data[time_column] < end_date)
|
|
726
736
|
]
|
|
727
737
|
else:
|
|
728
738
|
test_filtered = None
|
|
729
739
|
|
|
730
740
|
psi_df = self.calculate_psi(
|
|
731
|
-
filtered_data,
|
|
741
|
+
filtered_data,
|
|
742
|
+
test_filtered,
|
|
743
|
+
time_column,
|
|
744
|
+
time_expected,
|
|
745
|
+
num_buckets,
|
|
746
|
+
bucket_type,
|
|
732
747
|
)
|
|
733
748
|
|
|
734
749
|
fig = self.plot_psi(psi_df)
|
|
@@ -746,9 +761,9 @@ class UnivariateAnalysis:
|
|
|
746
761
|
|
|
747
762
|
def _calculate_psi_all(
|
|
748
763
|
self,
|
|
749
|
-
|
|
764
|
+
time_column: str,
|
|
750
765
|
time_expected: Union[str, datetime, date],
|
|
751
|
-
|
|
766
|
+
num_buckets: int,
|
|
752
767
|
bucket_type: Literal["quantile", "fixed_width"],
|
|
753
768
|
) -> pd.Series:
|
|
754
769
|
"""
|
|
@@ -756,11 +771,11 @@ class UnivariateAnalysis:
|
|
|
756
771
|
|
|
757
772
|
Parameters
|
|
758
773
|
----------
|
|
759
|
-
|
|
774
|
+
time_column : str
|
|
760
775
|
Name of the column that contains the observation date.
|
|
761
776
|
time_expected : Union[str, datetime, date]
|
|
762
777
|
The expected date for the PSI calculation.
|
|
763
|
-
|
|
778
|
+
num_buckets : int
|
|
764
779
|
Number of buckets for binning.
|
|
765
780
|
bucket_type : Literal["quantile", "fixed_width"]
|
|
766
781
|
The type of binning to use.
|
|
@@ -773,6 +788,6 @@ class UnivariateAnalysis:
|
|
|
773
788
|
dict_psi = {}
|
|
774
789
|
for num in self.numerical_features:
|
|
775
790
|
dict_psi[num] = self._calculate_psi_single(
|
|
776
|
-
|
|
791
|
+
time_column, time_expected, num, num_buckets, bucket_type
|
|
777
792
|
)
|
|
778
793
|
return pd.Series(dict_psi)
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/visualizations.py
RENAMED
|
@@ -21,7 +21,7 @@ class Visualizations:
|
|
|
21
21
|
|
|
22
22
|
def __init__(
|
|
23
23
|
self,
|
|
24
|
-
|
|
24
|
+
df: pd.DataFrame,
|
|
25
25
|
target_column: str,
|
|
26
26
|
numerical_columns: List[str],
|
|
27
27
|
categorical_columns: List[str],
|
|
@@ -31,7 +31,7 @@ class Visualizations:
|
|
|
31
31
|
|
|
32
32
|
Parameters
|
|
33
33
|
----------
|
|
34
|
-
|
|
34
|
+
df : pd.DataFrame
|
|
35
35
|
The data to be analyzed.
|
|
36
36
|
target_column : str
|
|
37
37
|
The target column for analysis.
|
|
@@ -40,7 +40,7 @@ class Visualizations:
|
|
|
40
40
|
categorical_columns : List[str]
|
|
41
41
|
List of categorical columns.
|
|
42
42
|
"""
|
|
43
|
-
self.data =
|
|
43
|
+
self.data = df
|
|
44
44
|
self.target_column = target_column
|
|
45
45
|
self.numerical_columns = numerical_columns
|
|
46
46
|
self.categorical_columns = categorical_columns
|
|
@@ -292,7 +292,7 @@ class Visualizations:
|
|
|
292
292
|
|
|
293
293
|
def visualize_high_cardinality(
|
|
294
294
|
self,
|
|
295
|
-
|
|
295
|
+
excluded_columns: List[str],
|
|
296
296
|
top_n: int = 10,
|
|
297
297
|
id_column: Optional[str] = None,
|
|
298
298
|
) -> None:
|
|
@@ -301,7 +301,7 @@ class Visualizations:
|
|
|
301
301
|
|
|
302
302
|
Parameters
|
|
303
303
|
----------
|
|
304
|
-
|
|
304
|
+
excluded_columns : List[str]
|
|
305
305
|
List of columns to exclude.
|
|
306
306
|
top_n : int, optional
|
|
307
307
|
Number of top categories to display, by default 10.
|
|
@@ -311,10 +311,10 @@ class Visualizations:
|
|
|
311
311
|
high_car, _ = self._check_cardinality()
|
|
312
312
|
|
|
313
313
|
if id_column:
|
|
314
|
-
|
|
314
|
+
excluded_columns.append(id_column)
|
|
315
315
|
|
|
316
316
|
# Exclude specified variables from the high cardinality list
|
|
317
|
-
high_car = [cat for cat in high_car if cat not in
|
|
317
|
+
high_car = [cat for cat in high_car if cat not in excluded_columns]
|
|
318
318
|
|
|
319
319
|
if not high_car:
|
|
320
320
|
print("No high cardinality features found.")
|
|
@@ -543,7 +543,7 @@ class Visualizations:
|
|
|
543
543
|
return vif_data
|
|
544
544
|
|
|
545
545
|
def _bin_and_target_freq(
|
|
546
|
-
self, variable_name: str,
|
|
546
|
+
self, variable_name: str, num_bins: int = 10, scale: bool = False
|
|
547
547
|
) -> pd.DataFrame:
|
|
548
548
|
"""
|
|
549
549
|
Bin a numerical variable and calculate target frequency.
|
|
@@ -552,7 +552,7 @@ class Visualizations:
|
|
|
552
552
|
----------
|
|
553
553
|
variable_name : str
|
|
554
554
|
Name of the numerical variable.
|
|
555
|
-
|
|
555
|
+
num_bins : int, optional
|
|
556
556
|
Number of bins to use, by default 10.
|
|
557
557
|
scale : bool, optional
|
|
558
558
|
Whether to scale the variable before binning, by default False.
|
|
@@ -562,15 +562,15 @@ class Visualizations:
|
|
|
562
562
|
pd.DataFrame
|
|
563
563
|
DataFrame with binned data and target frequency.
|
|
564
564
|
"""
|
|
565
|
-
|
|
565
|
+
df = self.data[[variable_name, self.target_column]].copy()
|
|
566
566
|
|
|
567
567
|
# Ensure target column is numeric (0 or 1)
|
|
568
|
-
|
|
568
|
+
df[self.target_column] = df[self.target_column].astype(int)
|
|
569
569
|
|
|
570
570
|
# Drop missing values and inform user
|
|
571
|
-
original_count = len(
|
|
572
|
-
|
|
573
|
-
dropped_count = original_count - len(
|
|
571
|
+
original_count = len(df)
|
|
572
|
+
df.dropna(subset=[variable_name], inplace=True)
|
|
573
|
+
dropped_count = original_count - len(df)
|
|
574
574
|
if dropped_count > 0:
|
|
575
575
|
print(
|
|
576
576
|
f"Dropped {dropped_count} rows with missing values for {variable_name}"
|
|
@@ -578,11 +578,11 @@ class Visualizations:
|
|
|
578
578
|
|
|
579
579
|
if scale:
|
|
580
580
|
# Scale the variable individually
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if
|
|
584
|
-
|
|
585
|
-
|
|
581
|
+
min_value = df[variable_name].min()
|
|
582
|
+
max_value = df[variable_name].max()
|
|
583
|
+
if min_value != max_value:
|
|
584
|
+
df[variable_name] = (df[variable_name] - min_value) / (
|
|
585
|
+
max_value - min_value
|
|
586
586
|
)
|
|
587
587
|
else:
|
|
588
588
|
print(
|
|
@@ -591,18 +591,18 @@ class Visualizations:
|
|
|
591
591
|
|
|
592
592
|
# Use 'drop' option to handle duplicate bin edges
|
|
593
593
|
try:
|
|
594
|
-
|
|
595
|
-
|
|
594
|
+
df["bin"] = pd.qcut(
|
|
595
|
+
df[variable_name], q=num_bins, labels=False, duplicates="drop"
|
|
596
596
|
)
|
|
597
597
|
except ValueError as e:
|
|
598
598
|
print(f"Warning: {e}")
|
|
599
599
|
print(
|
|
600
|
-
f"Attempting to create {
|
|
600
|
+
f"Attempting to create {num_bins} bins for {variable_name}, but some may be merged due to duplicate values."
|
|
601
601
|
)
|
|
602
602
|
# If qcut fails, fall back to cut with equal-width bins
|
|
603
|
-
|
|
603
|
+
df["bin"] = pd.cut(df[variable_name], bins=num_bins, labels=False)
|
|
604
604
|
|
|
605
|
-
grouped =
|
|
605
|
+
grouped = df.groupby("bin").agg(
|
|
606
606
|
{variable_name: "mean", self.target_column: ["count", "sum"]}
|
|
607
607
|
)
|
|
608
608
|
grouped.columns = PandasIndex([variable_name, "total_count", "target_sum"])
|
|
@@ -610,7 +610,7 @@ class Visualizations:
|
|
|
610
610
|
return grouped.reset_index()
|
|
611
611
|
|
|
612
612
|
def plot_hexagon_target_vs_numerical(
|
|
613
|
-
self, var1: str, var2: str,
|
|
613
|
+
self, var1: str, var2: str, num_bins: int = 20, scale: bool = False
|
|
614
614
|
) -> None:
|
|
615
615
|
"""
|
|
616
616
|
Create a hexbin plot comparing two numerical variables and their relationship to the target variable.
|
|
@@ -621,7 +621,7 @@ class Visualizations:
|
|
|
621
621
|
Name of the first numerical variable.
|
|
622
622
|
var2 : str
|
|
623
623
|
Name of the second numerical variable.
|
|
624
|
-
|
|
624
|
+
num_bins : int, optional
|
|
625
625
|
Number of bins to use, by default 20.
|
|
626
626
|
scale : bool, optional
|
|
627
627
|
Whether to scale variables before binning, by default False.
|
|
@@ -644,7 +644,7 @@ class Visualizations:
|
|
|
644
644
|
data[var1],
|
|
645
645
|
data[var2],
|
|
646
646
|
C=data[self.target_column],
|
|
647
|
-
gridsize=
|
|
647
|
+
gridsize=num_bins,
|
|
648
648
|
cmap="YlOrRd",
|
|
649
649
|
reduce_C_function=np.mean,
|
|
650
650
|
)
|
|
@@ -1203,46 +1203,3 @@ class Visualizations:
|
|
|
1203
1203
|
|
|
1204
1204
|
if show_plot:
|
|
1205
1205
|
fig.show()
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
'''
|
|
1209
|
-
def plot_categorical_value_counts(
|
|
1210
|
-
self, plot_type: Literal["bar", "pie"] = "bar"
|
|
1211
|
-
) -> None:
|
|
1212
|
-
"""
|
|
1213
|
-
Generate value counts for categorical features and visualize them.
|
|
1214
|
-
|
|
1215
|
-
Parameters
|
|
1216
|
-
----------
|
|
1217
|
-
plot_type : {'bar', 'pie'}, optional
|
|
1218
|
-
Type of plot to display, by default 'bar'.
|
|
1219
|
-
"""
|
|
1220
|
-
value_counts = {
|
|
1221
|
-
col: self.data[col].value_counts() for col in self.categorical_columns
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
for col in self.categorical_columns:
|
|
1225
|
-
counts = value_counts[col].reset_index()
|
|
1226
|
-
counts.columns = PandasIndex([col, "Frequency"])
|
|
1227
|
-
|
|
1228
|
-
if counts.empty:
|
|
1229
|
-
print(f"No data to plot for column: {col}")
|
|
1230
|
-
continue
|
|
1231
|
-
|
|
1232
|
-
if plot_type == "bar":
|
|
1233
|
-
fig = px.bar(
|
|
1234
|
-
counts, x=col, y="Frequency", title=f"Distribution of {col}"
|
|
1235
|
-
)
|
|
1236
|
-
elif plot_type == "pie":
|
|
1237
|
-
fig = px.pie(
|
|
1238
|
-
counts,
|
|
1239
|
-
names=col,
|
|
1240
|
-
values="Frequency",
|
|
1241
|
-
title=f"Distribution of {col}",
|
|
1242
|
-
)
|
|
1243
|
-
else:
|
|
1244
|
-
raise ValueError("plot_type should be either 'bar' or 'pie'")
|
|
1245
|
-
|
|
1246
|
-
fig.update_layout(title={"x": 0.5})
|
|
1247
|
-
fig.show()
|
|
1248
|
-
'''
|
|
File without changes
|
|
File without changes
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/bivariate_analysis.py
RENAMED
|
File without changes
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/eda/warnings/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{classifier_toolkit-0.1.2 → classifier_toolkit-0.1.4}/classifier_toolkit/feature_selection/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|