ML-Classify 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,159 @@
1
+
2
+ import pandas as pd
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ import math
6
+ import seaborn as sns
7
+ from sklearn.preprocessing import LabelEncoder
8
+
9
+ class EDA:
10
+ def __init__(self,X,y,numcol,catcol):
11
+ self.X = X
12
+ self.Y = y
13
+ self.numcol = numcol
14
+ self.catcol = catcol
15
+ self.num_col_name=[]
16
+ self.cat_col_name=[]
17
+ self.numericaldf=pd.DataFrame()
18
+ self.categoricaldf=pd.DataFrame()
19
+ self.__validate_and_assign_columns()
20
+ print(self.numcol,self.catcol,self.num_col_name)
21
+
22
+ # self.simulation_result_n={}
23
+ # self.simulation_result_one={}
24
+ # self.data_sim_one={}
25
+ # self.data_sim_n={}
26
+ # self.validate_and_assign_columns()
27
+
28
+
29
+ def __validate_and_assign_columns(self):
30
+ for idx, col in enumerate(self.X.columns):
31
+ if self.catcol[idx]==0:
32
+ self.num_col_name.append(col)
33
+ else:
34
+ self.X[col] = self.X[col].astype('category')
35
+ self.cat_col_name.append(col)
36
+
37
+ self.numericaldf=self.X[self.num_col_name]
38
+ self.categoricaldf=self.X[self.cat_col_name]
39
+
40
+
41
+
42
+ def PlotGraphs(self):
43
+ self.__bar_ylabel()
44
+ self.__categorical_counts()
45
+ self.__numerical_box_plot()
46
+ self.__corr_matrix()
47
+ self.__kde_plot()
48
+
49
+ def __bar_ylabel(self):
50
+ counts = self.Y.value_counts().sort_index()
51
+ plt.bar(counts.index, counts.values, edgecolor='black')
52
+ plt.title("Output Label Frequency")
53
+
54
+ def __categorical_counts(self):
55
+ if(len(self.cat_col_name)==0):
56
+ return "Na"
57
+ total_plots = len(self.cat_col_name)
58
+ cols = 3
59
+ rows = math.ceil(total_plots / cols)
60
+
61
+ fig_width = cols * 6
62
+ fig_height = rows * 6
63
+ fig,axes= plt.subplots(nrows=rows,
64
+ ncols=cols,
65
+ figsize=(fig_width, fig_height))
66
+
67
+ row,col=0,0
68
+ for colm in self.categoricaldf.columns:
69
+ counts = self.X[colm].value_counts().sort_index()
70
+ axes[row,col].bar(counts.index, counts.values, edgecolor='black')
71
+ axes[row,col].set_title(colm)
72
+ # axes.
73
+ # axes[row,col].set_ylabel()
74
+ col=col+1
75
+ if(col==3):
76
+ row+=1
77
+ col=(col)%cols
78
+
79
+ fig.suptitle("Categorical Counts", y=1)
80
+ plt.tight_layout(w_pad=2)
81
+ # plt.set_title("Categorical Counts")
82
+ plt.show()
83
+
84
+ def __numerical_box_plot(self):
85
+ total_plots = len(self.num_col_name)
86
+ cols = 3
87
+ rows = math.ceil(total_plots / cols)
88
+
89
+ fig_width = cols * 6
90
+ fig_height = rows * 6
91
+ fig,axes= plt.subplots(nrows=rows,
92
+ ncols=cols,
93
+ figsize=(fig_width, fig_height))
94
+
95
+ row,col=0,0
96
+ for colm in self.numericaldf.columns:
97
+ sns.boxplot(ax=axes[row,col],x=self.Y,y=self.X[colm])
98
+ axes[row,col].set_title(colm)
99
+
100
+ # axes.
101
+ # axes[row,col].set_ylabel()
102
+ col=col+1
103
+ if(col==3):
104
+ row+=1
105
+ col=(col)%cols
106
+
107
+ fig.suptitle("Distribution of Label with Respect to Numerical Features", y=1)
108
+ plt.tight_layout(w_pad=2)
109
+ # plt.set_title("Categorical Counts")
110
+ plt.show()
111
+
112
+ def __corr_matrix(self):
113
+ corrmatrix=self.numericaldf.corr(numeric_only=True)
114
+ plt.figure(figsize=(14, 10))
115
+ sns.heatmap(corrmatrix, annot=True, cmap="coolwarm", fmt=".2f", linewidths=0.1)
116
+ plt.show()
117
+
118
+ def __kde_plot(self):
119
+
120
+ Lable_Enc=LabelEncoder()
121
+ y_encoded = Lable_Enc.fit_transform(self.Y)
122
+ total_plots = len(self.num_col_name)
123
+ cols = 3
124
+ rows = math.ceil(total_plots / cols)
125
+
126
+ fig_width = cols * 6
127
+ fig_height = rows * 6
128
+
129
+ fig, axes = plt.subplots(
130
+ nrows=rows,
131
+ ncols=cols,
132
+ figsize=(fig_width, fig_height),
133
+ # constrained_layout=True
134
+ )
135
+ row,col=0,0
136
+ classes=np.unique(y_encoded)
137
+ colors = sns.color_palette("Set1", n_colors=len(classes))
138
+
139
+ for i in self.numericaldf.columns:
140
+ for j, color in zip(classes, colors):
141
+ sns.kdeplot(
142
+ self.X.loc[y_encoded == j, i],
143
+ color=color,
144
+ label=f'{Lable_Enc.inverse_transform([j])[0]} class',
145
+ ax=axes[row,col],
146
+ fill=True
147
+ )
148
+
149
+ axes[row, col].legend()
150
+ col=col+1
151
+ if(col==3):
152
+ row+=1
153
+ col=(col)%cols
154
+
155
+ plt.tight_layout(w_pad=2)
156
+ plt.show()
157
+
158
+
159
+
@@ -0,0 +1,832 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from sklearn.preprocessing import OneHotEncoder, StandardScaler
4
+ from sklearn.pipeline import Pipeline,make_pipeline
5
+ from sklearn.compose import ColumnTransformer
6
+ from sklearn.impute import SimpleImputer
7
+ from sklearn.model_selection import train_test_split
8
+ from imblearn.over_sampling import SMOTENC
9
+ from imblearn.under_sampling import RandomUnderSampler
10
+ from sklearn.datasets import load_breast_cancer
11
+ from imblearn.over_sampling import SMOTEN
12
+
13
+
14
+ from sklearn.preprocessing import LabelEncoder
15
+ from sklearn.preprocessing import label_binarize
16
+ from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier, OutputCodeClassifier
17
+
18
+ from sklearn.model_selection import GridSearchCV
19
+ from sklearn.model_selection import StratifiedKFold, cross_val_score
20
+ from sklearn.linear_model import LogisticRegression
21
+ from sklearn.tree import DecisionTreeClassifier
22
+ from sklearn.svm import SVC
23
+ import random
24
+
25
+ from .EDA import EDA
26
+ from sklearn.metrics import (
27
+ accuracy_score,
28
+ recall_score,
29
+ precision_score,
30
+ f1_score,
31
+ roc_auc_score,
32
+ confusion_matrix
33
+ )
34
+ from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
35
+ # from abc import ABC, abstractclassmethod
36
+
37
+ class PyClassify():
38
+ def __init__(self,X,y,numcol,catcol):
39
+ self.X = X
40
+ self.y = y
41
+ self.numcol = numcol
42
+ self.catcol = catcol
43
+ self.simulation_result_n={}
44
+ self.simulation_result_one={}
45
+ self.data_sim_one={}
46
+ self.data_sim_n={}
47
+ self.validate_and_assign_columns()
48
+
49
+ def validate_and_assign_columns(self):
50
+ numeric_cols=[]
51
+ cat_cols=[]
52
+ for Num,Cat,Col in zip(self.numcol,self.catcol,self.X.columns.tolist()):
53
+ if(Num==1 and Cat==1):
54
+ raise Exception("Column could not be both cat and num.")
55
+
56
+ if(Num==1):
57
+ numeric_cols.append(Col)
58
+ elif(Cat==1):
59
+ cat_cols.append(Col)
60
+ else:
61
+ raise Exception("A column has to be cat/numeric.")
62
+ self.numcol=numeric_cols
63
+ self.catcol=cat_cols
64
+
65
+
66
+ def preprocess(self, EncodeCat=False,EncodeLabel=False,seed=42,sampling=2):
67
+
68
+ '''
69
+ other logic would be apply one hot and std scaler the in last apply smote
70
+ then it would have 1 final pipline
71
+
72
+ '''
73
+
74
+ '''
75
+ Docstring for preprocess
76
+
77
+ :param EncodeCat: by default false
78
+ :param EncodeLabel: by default false
79
+ :param seed:
80
+ :param sampling: 0 for no sampling, 1 for undersampling, 2 for oversampling
81
+ '''
82
+
83
+ # label encoding
84
+ if EncodeLabel:
85
+ self.label_encoder = LabelEncoder()
86
+ y_encoded = self.label_encoder.fit_transform(self.y)
87
+ else:
88
+ y_encoded = self.y
89
+
90
+ X_train,X_test,y_train,y_test=train_test_split(self.X,y_encoded,random_state=seed,test_size=0.3, stratify=y_encoded)
91
+
92
+
93
+ # standardization
94
+ numeric_pipeline = Pipeline(steps=[
95
+ ("imputer", SimpleImputer(strategy="mean")),
96
+ ("scaler", StandardScaler())
97
+ ])
98
+ # numeric_processor = make_pipeline(
99
+ # SimpleImputer(strategy="mean"),
100
+ # StandardScaler()
101
+ # )
102
+
103
+ scale_transformer = ColumnTransformer(
104
+ transformers=[
105
+ ("num", numeric_pipeline, self.numcol)
106
+ ],
107
+ remainder="passthrough" # keep categorical untouched
108
+ )
109
+
110
+ X_train_scaled = scale_transformer.fit_transform(X_train)
111
+ X_test_scaled = scale_transformer.transform(X_test)
112
+
113
+ # smotenc
114
+ original_cols = list(self.X.columns)
115
+ remainder_cols = [col for col in original_cols if col not in self.numcol]
116
+
117
+ cat_indices = [
118
+ len(self.numcol) + remainder_cols.index(cat_col)
119
+ for cat_col in self.catcol
120
+ ]
121
+
122
+ if sampling==0:
123
+
124
+ X_train_res,y_train_res=X_train_scaled,y_train
125
+
126
+ elif sampling==1:
127
+
128
+ rus = RandomUnderSampler(sampling_strategy='majority')
129
+ X_train_res, y_train_res = rus.fit_resample(X_train_scaled, y_train)
130
+
131
+ elif sampling==2:
132
+ if (1 in self.numcol):
133
+
134
+ smote = SMOTENC(
135
+ categorical_features=cat_indices
136
+ )
137
+ X_train_res, y_train_res = smote.fit_resample(
138
+ X_train_scaled, y_train)
139
+ else:
140
+ smote = SMOTEN(random_state=42)
141
+
142
+ X_train_res, y_train_res = smote.fit_resample(
143
+ X_train_scaled, y_train
144
+ )
145
+ else:
146
+ raise ValueError("invalid sampling input")
147
+
148
+
149
+ print('After Sampling train_X: {}'.format(X_train_res.shape))
150
+ print('After Sampling train_y: {} \n'.format(y_train_res.shape))
151
+
152
+
153
+ # numeric_processor=Pipeline(
154
+ # steps=[("imputation_mean",SimpleImputer(missing_values=np.nan,strategy="mean")),
155
+ # ("scaler",StandardScaler())]
156
+ # )
157
+
158
+
159
+
160
+
161
+ # one hot
162
+ cat_processor=make_pipeline(
163
+ OneHotEncoder(handle_unknown="ignore")
164
+ )
165
+ cat_transformer = cat_processor if EncodeCat else "passthrough"
166
+
167
+ Cat_transformation= ColumnTransformer([
168
+ ('cat', cat_transformer, cat_indices)],
169
+ remainder='passthrough')
170
+
171
+ x_train_final = Cat_transformation.fit_transform(X_train_res)
172
+ x_test_final = Cat_transformation.transform(X_test_scaled)
173
+
174
+ return x_train_final,x_test_final,y_train_res,y_test
175
+
176
+
177
+
178
+
179
+
180
+ class Binclassification:
181
+ def __init__(self,X,y,numcol,catcol):
182
+ self.X = X
183
+ self.y = y
184
+ self.numcol_onehot=numcol
185
+ self.catcol_onehot=catcol
186
+ self.numcol = numcol
187
+ self.catcol = catcol
188
+ self.simulation_result_n={}
189
+ self.simulation_result_one={}
190
+ self.data_sim_one={}
191
+ self.data_sim_n={}
192
+ self.validate_and_assign_columns()
193
+
194
+
195
+ def validate_and_assign_columns(self):
196
+ numeric_cols=[]
197
+ cat_cols=[]
198
+ for Num,Cat,Col in zip(self.numcol,self.catcol,self.X.columns.tolist()):
199
+ if(Num==1 and Cat==1):
200
+ raise Exception("Column could not be both cat and num.")
201
+
202
+ if(Num==1):
203
+ numeric_cols.append(Col)
204
+ elif(Cat==1):
205
+ cat_cols.append(Col)
206
+ else:
207
+ raise Exception("A column has to be cat/numeric.")
208
+ self.numcol=numeric_cols
209
+ self.catcol=cat_cols
210
+
211
+ def EDA(self):
212
+ EDAobject= EDA(X=self.X,y=self.y, numcol=self.numcol_onehot,catcol=self.catcol_onehot )
213
+ EDAobject.PlotGraphs()
214
+
215
+
216
+ def preprocess(self, EncodeCat=False,EncodeLabel=False,seed=42,sampling=2):
217
+
218
+ '''
219
+ other logic would be apply one hot and std scaler the in last apply smote
220
+ then it would have 1 final pipline
221
+
222
+ '''
223
+
224
+ '''
225
+ Docstring for preprocess
226
+
227
+ :param EncodeCat: by default false
228
+ :param EncodeLabel: by default false
229
+ :param seed:
230
+ :param sampling: 0 for no sampling, 1 for undersampling, 2 for oversampling
231
+ '''
232
+
233
+ # label encoding
234
+ if EncodeLabel:
235
+ self.label_encoder = LabelEncoder()
236
+ y_encoded = self.label_encoder.fit_transform(self.y)
237
+ else:
238
+ y_encoded = self.y
239
+
240
+ X_train,X_test,y_train,y_test=train_test_split(self.X,y_encoded,random_state=seed,test_size=0.3, stratify=y_encoded)
241
+
242
+
243
+ # standardization
244
+ numeric_pipeline = Pipeline(steps=[
245
+ ("imputer", SimpleImputer(strategy="mean")),
246
+ ("scaler", StandardScaler())
247
+ ])
248
+ # numeric_processor = make_pipeline(
249
+ # SimpleImputer(strategy="mean"),
250
+ # StandardScaler()
251
+ # )
252
+
253
+ scale_transformer = ColumnTransformer(
254
+ transformers=[
255
+ ("num", numeric_pipeline, self.numcol)
256
+ ],
257
+ remainder="passthrough" # keep categorical untouched
258
+ )
259
+
260
+ X_train_scaled = scale_transformer.fit_transform(X_train)
261
+ X_test_scaled = scale_transformer.transform(X_test)
262
+
263
+ # smotenc
264
+ original_cols = list(self.X.columns)
265
+ remainder_cols = [col for col in original_cols if col not in self.numcol]
266
+
267
+ cat_indices = [
268
+ len(self.numcol) + remainder_cols.index(cat_col)
269
+ for cat_col in self.catcol
270
+ ]
271
+
272
+ if sampling==0:
273
+
274
+ X_train_res,y_train_res=X_train_scaled,y_train
275
+
276
+ elif sampling==1:
277
+
278
+ rus = RandomUnderSampler(sampling_strategy='majority')
279
+ X_train_res, y_train_res = rus.fit_resample(X_train_scaled, y_train)
280
+
281
+ elif sampling==2:
282
+ if (1 in self.numcol):
283
+
284
+ smote = SMOTENC(
285
+ categorical_features=cat_indices
286
+ )
287
+ X_train_res, y_train_res = smote.fit_resample(
288
+ X_train_scaled, y_train)
289
+ else:
290
+ smote = SMOTEN(random_state=42)
291
+
292
+ X_train_res, y_train_res = smote.fit_resample(
293
+ X_train_scaled, y_train
294
+ )
295
+ else:
296
+ raise ValueError("invalid sampling input")
297
+
298
+
299
+ print('After Sampling train_X: {}'.format(X_train_res.shape))
300
+ print('After Sampling train_y: {} \n'.format(y_train_res.shape))
301
+
302
+
303
+ # numeric_processor=Pipeline(
304
+ # steps=[("imputation_mean",SimpleImputer(missing_values=np.nan,strategy="mean")),
305
+ # ("scaler",StandardScaler())]
306
+ # )
307
+
308
+
309
+
310
+
311
+ # one hot
312
+ cat_processor=make_pipeline(
313
+ OneHotEncoder(handle_unknown="ignore")
314
+ )
315
+ cat_transformer = cat_processor if EncodeCat else "passthrough"
316
+
317
+ Cat_transformation= ColumnTransformer([
318
+ ('cat', cat_transformer, cat_indices)],
319
+ remainder='passthrough')
320
+
321
+ x_train_final = Cat_transformation.fit_transform(X_train_res)
322
+ x_test_final = Cat_transformation.transform(X_test_scaled)
323
+
324
+ return x_train_final,x_test_final,y_train_res,y_test
325
+
326
+
327
+
328
+ def _run_simulation(self, EncodeCat, EncodeLabel, seed, sampling):
329
+ X_train, X_test, y_train, y_test = self.preprocess(EncodeCat,EncodeLabel,seed,sampling)
330
+
331
+ results = {}
332
+
333
+ models = {
334
+ "LogisticRegression": (
335
+ LogisticRegression(max_iter=5000),
336
+ {
337
+ 'C': np.logspace(-4, 4, 20),
338
+ "penalty": ["l1", "l2"],
339
+ "solver": ["liblinear"]
340
+ }
341
+ ),
342
+ "SVC": (
343
+ SVC(probability=True,max_iter=1000),
344
+ {
345
+ 'C': [0.1, 1, 10],
346
+ 'gamma': [0.01, 0.1, 1],
347
+ 'kernel': ['linear',"rbf"]
348
+ }
349
+ ),
350
+ "DecisionTree": (
351
+ DecisionTreeClassifier(),
352
+ {
353
+ 'max_depth': range(1, 15),
354
+ 'min_samples_leaf': range(1, 20, 2),
355
+ 'min_samples_split': range(2, 20, 2),
356
+ 'criterion': ["entropy", "gini"]
357
+ }
358
+ ),
359
+ "RandomForest": (
360
+ RandomForestClassifier(),
361
+ {
362
+ 'n_estimators': [100, 200, 300],
363
+ 'max_depth': [None, 5, 10, 20],
364
+ 'min_samples_split': [2, 5, 10],
365
+ 'min_samples_leaf': [1, 2, 4]
366
+ }
367
+ ),
368
+ "AdaBoost": (
369
+ AdaBoostClassifier(),
370
+ {
371
+ 'n_estimators': [50, 100, 200],
372
+ 'learning_rate': [0.01, 0.1, 1]
373
+ }
374
+ ),
375
+ }
376
+
377
+
378
+ for name, (model, params) in models.items():
379
+ print("inside the loop 1")
380
+
381
+ grid = GridSearchCV(
382
+ estimator=model,
383
+ param_grid=params,
384
+ cv=StratifiedKFold(10),
385
+ scoring='accuracy',
386
+ n_jobs=-1,
387
+ verbose=True
388
+ )
389
+
390
+ grid.fit(X_train, y_train)
391
+
392
+ best_model = grid.best_estimator_
393
+
394
+ y_pred = best_model.predict(X_test)
395
+
396
+ if hasattr(best_model, "predict_proba"):
397
+ y_prob = best_model.predict_proba(X_test)[:, 1]
398
+ else:
399
+ y_prob = best_model.decision_function(X_test)
400
+
401
+ acc = accuracy_score(y_test, y_pred)
402
+ sensitivity = recall_score(y_test, y_pred)
403
+ precision = precision_score(y_test, y_pred)
404
+ f1 = f1_score(y_test, y_pred)
405
+ auc = roc_auc_score(y_test, y_prob)
406
+
407
+ tn, fp, fn, tp = confusion_matrix(y_test, y_pred).ravel()
408
+ specificity = tn / (tn + fp)
409
+
410
+ results[name] = {
411
+ "best_estimator": grid.best_estimator_,
412
+ "best_score": grid.best_score_,
413
+ "best_params": grid.best_params_,
414
+ "test_result": {
415
+ "Accuracy": acc,
416
+ "Sensitivity": sensitivity,
417
+ "Specificity": specificity,
418
+ "Precision": precision,
419
+ "F1-score": f1,
420
+ "AUC": auc
421
+ }
422
+ }
423
+
424
+ data = {
425
+ "X_train":X_train,
426
+ "X_test":X_test,
427
+ "y_train":y_train,
428
+ "y_test":y_test
429
+ }
430
+
431
+ return data, results
432
+
433
+
434
+ def simulate_one(self, EncodeCat=False, EncodeLabel=False, seed=42, sampling=2):
435
+
436
+ data, results = self._run_simulation(
437
+ EncodeCat, EncodeLabel, seed, sampling
438
+ )
439
+
440
+ self.data_sim_one[f"seed {seed}"] = data
441
+ self.simulation_result_one[f"seed {seed}"] = results
442
+
443
+ # return results
444
+
445
+
446
+
447
+
448
+
449
+ def simulate_ntimes(self, n=5, EncodeCat=False, EncodeLabel=False, sampling=2):
450
+
451
+ seeds = random.sample(range(1, 101), n)
452
+
453
+ for seed in seeds:
454
+
455
+ data, results = self._run_simulation(
456
+ EncodeCat, EncodeLabel, seed, sampling
457
+ )
458
+
459
+ self.data_sim_n[f"seed {seed}"] = data
460
+ self.simulation_result_n[f"seed {seed}"] = results
461
+
462
+ # return self.simulation_result_n
463
+
464
+ # def preprocess(self, EncodeCat=False,EncodeLabel=False,seed=42,sampling=2):
465
+
466
+ # '''
467
+ # Docstring for preprocess
468
+
469
+ # :param EncodeCat: by default false
470
+ # :param EncodeLabel: by default false
471
+ # :param seed:
472
+ # :param sampling: 0 for no sampling, 1 for undersampling, 2 for oversampling
473
+ # '''
474
+
475
+
476
+
477
+ # X_train,X_test,y_train,y_test=train_test_split(self.X,self.y,random_state=seed,test_size=0.3, stratify=self.y)
478
+
479
+ # numeric_pipeline = Pipeline(steps=[
480
+ # ("imputer", SimpleImputer(strategy="mean")),
481
+ # ("scaler", StandardScaler())
482
+ # ])
483
+ # # numeric_processor = make_pipeline(
484
+ # # SimpleImputer(strategy="mean"),
485
+ # # StandardScaler()
486
+ # # )
487
+ # scale_transformer = ColumnTransformer(
488
+ # transformers=[
489
+ # ("num", numeric_pipeline, self.numcol)
490
+ # ],
491
+ # remainder="passthrough" # keep categorical untouched
492
+ # )
493
+
494
+ # X_train_scaled = scale_transformer.fit_transform(X_train)
495
+ # X_test_scaled = scale_transformer.transform(X_test)
496
+
497
+ # if sampling==0:
498
+
499
+ # X_train_res,y_train_res=X_train,y_train
500
+
501
+ # if sampling==1:
502
+
503
+ # rus = RandomUnderSampler(sampling_strategy='majority')
504
+ # X_train_res, y_train_res = rus.fit_resample(X_train_scaled, y_train)
505
+
506
+ # elif sampling==2:
507
+ # cat_indices = self.X.columns.get_indexer(self.catcol)
508
+ # smote = SMOTENC(
509
+ # categorical_features=cat_indices
510
+ # )
511
+ # X_train_res, y_train_res = smote.fit_resample(
512
+ # X_train_scaled, y_train)
513
+
514
+ # else:
515
+ # raise "invalid sampling input"
516
+
517
+
518
+ # print('After Sampling train_X: {}'.format(X_train_res.shape))
519
+ # print('After Sampling train_y: {} \n'.format(y_train_res.shape))
520
+
521
+
522
+ # # numeric_processor=Pipeline(
523
+ # # steps=[("imputation_mean",SimpleImputer(missing_values=np.nan,strategy="mean")),
524
+ # # ("scaler",StandardScaler())]
525
+ # # )
526
+
527
+
528
+
529
+ # cat_processor=make_pipeline(
530
+ # OneHotEncoder(handle_unknown="ignore")
531
+ # )
532
+ # cat_transformer = cat_processor if EncodeCat else "passthrough"
533
+
534
+ # Cat_transformation= ColumnTransformer([
535
+ # ("num",numeric_pipeline,self.numcol)
536
+ # ('cat', cat_transformer, self.catcol)])
537
+
538
+ # x_train_final = Cat_transformation.fit_transform(X_train_res)
539
+ # x_test_final = Cat_transformation.transform(X_test_scaled)
540
+ # return x_train_final,x_test_final,y_train_res,y_test
541
+
542
+ from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier
543
+ from sklearn.metrics import classification_report
544
+ from sklearn.preprocessing import label_binarize
545
+ from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier, OutputCodeClassifier
546
+ from sklearn.svm import SVC
547
+
548
+ class MulticlassClassification:
549
+ def __init__(self,X,y,numcol,catcol):
550
+ self.X = X
551
+ self.y = y
552
+ self.numcol_onehot=numcol
553
+ self.catcol_onehot=catcol
554
+ self.numcol = numcol
555
+ self.catcol = catcol
556
+ self.simulation_result_n={}
557
+ self.simulation_result_one={}
558
+ self.data_sim_one={}
559
+ self.data_sim_n={}
560
+ self.validate_and_assign_columns()
561
+
562
+
563
+ def validate_and_assign_columns(self):
564
+ numeric_cols = []
565
+ cat_cols = []
566
+
567
+ for Num, Cat, Col in zip(self.numcol, self.catcol, self.X.columns.tolist()):
568
+ if Num == 1 and Cat == 1:
569
+ raise Exception("Column cannot be both categorical and numeric")
570
+
571
+ if Num == 1:
572
+ numeric_cols.append(Col)
573
+ elif Cat == 1:
574
+ cat_cols.append(Col)
575
+ else:
576
+ raise Exception("Column must be either numeric or categorical")
577
+
578
+ self.numcol = numeric_cols
579
+ self.catcol = cat_cols
580
+
581
+ def preprocess(self, EncodeCat=False,EncodeLabel=False,seed=42,sampling=2):
582
+
583
+ '''
584
+ other logic would be apply one hot and std scaler the in last apply smote
585
+ then it would have 1 final pipline
586
+
587
+ '''
588
+
589
+ '''
590
+ Docstring for preprocess
591
+
592
+ :param EncodeCat: by default false
593
+ :param EncodeLabel: by default false
594
+ :param seed:
595
+ :param sampling: 0 for no sampling, 1 for undersampling, 2 for oversampling
596
+ '''
597
+
598
+ # label encoding
599
+ if EncodeLabel:
600
+ self.label_encoder = LabelEncoder()
601
+ y_encoded = self.label_encoder.fit_transform(self.y)
602
+ else:
603
+ y_encoded = self.y
604
+
605
+ X_train,X_test,y_train,y_test=train_test_split(self.X,y_encoded,random_state=seed,test_size=0.3, stratify=y_encoded)
606
+
607
+
608
+ # standardization
609
+ numeric_pipeline = Pipeline(steps=[
610
+ ("imputer", SimpleImputer(strategy="mean")),
611
+ ("scaler", StandardScaler())
612
+ ])
613
+ # numeric_processor = make_pipeline(
614
+ # SimpleImputer(strategy="mean"),
615
+ # StandardScaler()
616
+ # )
617
+
618
+ scale_transformer = ColumnTransformer(
619
+ transformers=[
620
+ ("num", numeric_pipeline, self.numcol)
621
+ ],
622
+ remainder="passthrough" # keep categorical untouched
623
+ )
624
+
625
+ X_train_scaled = scale_transformer.fit_transform(X_train)
626
+ X_test_scaled = scale_transformer.transform(X_test)
627
+
628
+ # smotenc
629
+ original_cols = list(self.X.columns)
630
+ remainder_cols = [col for col in original_cols if col not in self.numcol]
631
+
632
+ cat_indices = [
633
+ len(self.numcol) + remainder_cols.index(cat_col)
634
+ for cat_col in self.catcol
635
+ ]
636
+
637
+ if sampling==0:
638
+
639
+ X_train_res,y_train_res=X_train_scaled,y_train
640
+
641
+ elif sampling==1:
642
+
643
+ rus = RandomUnderSampler(sampling_strategy='majority')
644
+ X_train_res, y_train_res = rus.fit_resample(X_train_scaled, y_train)
645
+
646
+ elif sampling==2:
647
+ if (1 in self.numcol):
648
+
649
+ smote = SMOTENC(
650
+ categorical_features=cat_indices
651
+ )
652
+ X_train_res, y_train_res = smote.fit_resample(
653
+ X_train_scaled, y_train)
654
+ else:
655
+ smote = SMOTEN(random_state=42)
656
+
657
+ X_train_res, y_train_res = smote.fit_resample(
658
+ X_train_scaled, y_train
659
+ )
660
+ else:
661
+ raise ValueError("invalid sampling input")
662
+
663
+
664
+ print('After Sampling train_X: {}'.format(X_train_res.shape))
665
+ print('After Sampling train_y: {} \n'.format(y_train_res.shape))
666
+
667
+
668
+ # numeric_processor=Pipeline(
669
+ # steps=[("imputation_mean",SimpleImputer(missing_values=np.nan,strategy="mean")),
670
+ # ("scaler",StandardScaler())]
671
+ # )
672
+
673
+
674
+
675
+
676
+ # one hot
677
+ cat_processor=make_pipeline(
678
+ OneHotEncoder(handle_unknown="ignore")
679
+ )
680
+ cat_transformer = cat_processor if EncodeCat else "passthrough"
681
+
682
+ Cat_transformation= ColumnTransformer([
683
+ ('cat', cat_transformer, cat_indices)],
684
+ remainder='passthrough')
685
+
686
+ x_train_final = Cat_transformation.fit_transform(X_train_res)
687
+ x_test_final = Cat_transformation.transform(X_test_scaled)
688
+
689
+ return x_train_final,x_test_final,y_train_res,y_test
690
+
691
+
692
+ def EDA(self):
693
+ EDAobject= EDA(X=self.X,y=self.y, numcol=self.numcol_onehot,catcol=self.catcol_onehot )
694
+ EDAobject.PlotGraphs()
695
+
696
+ def _run_simulation(self, EncodeCat, EncodeLabel, seed, sampling):
697
+
698
+ X_train, X_test, y_train, y_test = self.preprocess(
699
+ EncodeCat, EncodeLabel, seed, sampling
700
+ )
701
+
702
+ results = {}
703
+ models={
704
+ "LogisticRegression_OvR": (
705
+ OneVsRestClassifier(LogisticRegression(max_iter=5000)),
706
+ {
707
+ "estimator__C": np.logspace(-4, 4, 10)
708
+ }
709
+ ),
710
+
711
+ "SVC_OvR": (
712
+ OneVsRestClassifier(SVC(probability=True)),
713
+ {
714
+ "estimator__C": [0.1, 1, 10],
715
+ "estimator__gamma": [0.01, 0.1],
716
+ "estimator__kernel": ["linear", "rbf"]
717
+ }
718
+ ),
719
+
720
+ "SVC_OvO": (
721
+ OneVsOneClassifier(SVC(probability=True)),
722
+ {
723
+ "estimator__C": [0.1, 1, 10],
724
+ "estimator__gamma": [0.01, 0.1],
725
+ "estimator__kernel": ["linear", "rbf"]
726
+ }
727
+ ),
728
+
729
+ "SVC_ECOC": (
730
+ OutputCodeClassifier(SVC(probability=True)),
731
+ {
732
+ "estimator__C": [0.1, 1, 10],
733
+ "estimator__gamma": [0.01, 0.1],
734
+ "estimator__kernel": ["linear", "rbf"],
735
+ "code_size": [1.5, 2]
736
+ }
737
+ ),
738
+
739
+ }
740
+
741
+ for name, (model, params) in models.items():
742
+ print(f"Training {name}...")
743
+
744
+ grid = GridSearchCV(
745
+ estimator=model,
746
+ param_grid=params,
747
+ cv=StratifiedKFold(10),
748
+ scoring='accuracy',
749
+ n_jobs=-1,
750
+ verbose=1
751
+ )
752
+
753
+ grid.fit(X_train, y_train)
754
+ best_model = grid.best_estimator_
755
+
756
+ y_pred = best_model.predict(X_test)
757
+ # if hasattr(best_model, "predict_proba"):
758
+ # y_prob = best_model.predict_proba(X_test)
759
+
760
+ # elif hasattr(best_model, "decision_function"):
761
+ # y_prob = best_model.decision_function(X_test)
762
+
763
+ # else:
764
+ # y_prob = best_model.predict(X_test)
765
+
766
+
767
+ acc = accuracy_score(y_test, y_pred)
768
+ recall = recall_score(y_test, y_pred, average="macro")
769
+ precision = precision_score(y_test, y_pred, average="macro")
770
+ f1 = f1_score(y_test, y_pred, average="macro")
771
+
772
+ classes = np.unique(y_train)
773
+ # y_test_bin = label_binarize(y_test, classes=classes)
774
+
775
+ # auc = roc_auc_score(
776
+ # y_test_bin,
777
+ # y_prob,
778
+ # multi_class="ovr",
779
+ # average="macro"
780
+ # )
781
+
782
+ cm = confusion_matrix(y_test, y_pred)
783
+
784
+ results[name] = {
785
+ "best_estimator": best_model,
786
+ "best_score": grid.best_score_,
787
+ "best_params": grid.best_params_,
788
+ "test_result": {
789
+ "Accuracy": acc,
790
+ "Recall (Macro)": recall,
791
+ "Precision (Macro)": precision,
792
+ "F1-score (Macro)": f1,
793
+ # "AUC (OvR Macro)": auc,
794
+ "ConfusionMatrix": cm
795
+ }
796
+ }
797
+
798
+ data = {
799
+ "X_train": X_train,
800
+ "X_test": X_test,
801
+ "y_train": y_train,
802
+ "y_test": y_test
803
+ }
804
+
805
+ return data, results
806
+
807
+ def simulate_one(self, EncodeCat=True, EncodeLabel=True, seed=42, sampling=2):
808
+
809
+ data, results = self._run_simulation(
810
+ EncodeCat, EncodeLabel, seed, sampling
811
+ )
812
+
813
+ self.data_sim_one[f"seed {seed}"] = data
814
+ self.simulation_result_one[f"seed {seed}"] = results
815
+
816
+
817
+
818
+
819
+
820
+
821
+ def simulate_ntimes(self, n=5, EncodeCat=True, EncodeLabel=True, sampling=2):
822
+
823
+ seeds = random.sample(range(1, 101), n)
824
+
825
+ for seed in seeds:
826
+
827
+ data, results = self._run_simulation(
828
+ EncodeCat, EncodeLabel, seed, sampling
829
+ )
830
+
831
+ self.data_sim_n[f"seed {seed}"] = data
832
+ self.simulation_result_n[f"seed {seed}"] = results
@@ -0,0 +1,2 @@
1
+ from .Model import PyClassify, Binclassification, MulticlassClassification
2
+ from .EDA import EDA
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: ML_Classify
3
+ Version: 0.1.0
4
+ Summary: My Python package ml classify lib
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy
8
+ Requires-Dist: pandas
9
+ Requires-Dist: scikit-learn
10
+ Requires-Dist: imbalanced-learn
11
+ Requires-Dist: imblearn
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: seaborn
14
+
15
+ # My Package
16
+
17
+ My Python package containing machine learning models and EDA utilities.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install ML_Classify
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ ML_Classify/EDA.py
4
+ ML_Classify/Model.py
5
+ ML_Classify/__init__.py
6
+ ML_Classify.egg-info/PKG-INFO
7
+ ML_Classify.egg-info/SOURCES.txt
8
+ ML_Classify.egg-info/dependency_links.txt
9
+ ML_Classify.egg-info/requires.txt
10
+ ML_Classify.egg-info/top_level.txt
@@ -0,0 +1,7 @@
1
+ numpy
2
+ pandas
3
+ scikit-learn
4
+ imbalanced-learn
5
+ imblearn
6
+ matplotlib
7
+ seaborn
@@ -0,0 +1 @@
1
+ ML_Classify
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: ML_Classify
3
+ Version: 0.1.0
4
+ Summary: My Python package ml classify lib
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy
8
+ Requires-Dist: pandas
9
+ Requires-Dist: scikit-learn
10
+ Requires-Dist: imbalanced-learn
11
+ Requires-Dist: imblearn
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: seaborn
14
+
15
+ # My Package
16
+
17
+ My Python package containing machine learning models and EDA utilities.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install ML_Classify
@@ -0,0 +1,8 @@
1
+ # My Package
2
+
3
+ My Python package containing machine learning models and EDA utilities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install ML_Classify
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ML_Classify"
7
+ version = "0.1.0"
8
+ description = "My Python package ml classify lib"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+
12
+ dependencies = [
13
+ "numpy",
14
+ "pandas",
15
+ "scikit-learn",
16
+ "imbalanced-learn",
17
+ "imblearn",
18
+ "matplotlib",
19
+ "seaborn",
20
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+