SuperModelingFactory 0.2.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 (79) hide show
  1. ExcelMaster/ExcelFormatTool.py +487 -0
  2. ExcelMaster/ExcelMaster.py +917 -0
  3. ExcelMaster/Template.py +525 -0
  4. ExcelMaster/Utility.py +233 -0
  5. ExcelMaster/__init__.py +3 -0
  6. Modeling_Tool/Core/Binning_Tool.py +1608 -0
  7. Modeling_Tool/Core/Binning_Tool.pyi +48 -0
  8. Modeling_Tool/Core/Check_DuckDB_Compatibility.py +835 -0
  9. Modeling_Tool/Core/Json_Data_Converter.py +621 -0
  10. Modeling_Tool/Core/Model_Registry_Tool.py +199 -0
  11. Modeling_Tool/Core/ODPS_Tool.py +284 -0
  12. Modeling_Tool/Core/Slope_Tool.py +356 -0
  13. Modeling_Tool/Core/Slope_Tool.pyi +31 -0
  14. Modeling_Tool/Core/XOR_Encryptor.py +207 -0
  15. Modeling_Tool/Core/XOR_Encryptor.pyi +26 -0
  16. Modeling_Tool/Core/__init__.py +99 -0
  17. Modeling_Tool/Core/kDataFrame.py +228 -0
  18. Modeling_Tool/Core/kDataFrame.pyi +43 -0
  19. Modeling_Tool/Core/sample_weight_utils.py +77 -0
  20. Modeling_Tool/Core/utils.py +2672 -0
  21. Modeling_Tool/Eval/Evaluation_Tool.py +1452 -0
  22. Modeling_Tool/Eval/Evaluation_Tool.pyi +47 -0
  23. Modeling_Tool/Eval/Model_Eval_Tool.py +2548 -0
  24. Modeling_Tool/Eval/Model_Eval_Tool.pyi +37 -0
  25. Modeling_Tool/Eval/__init__.py +54 -0
  26. Modeling_Tool/Eval/evaluate_model.py +2008 -0
  27. Modeling_Tool/Eval/evaluate_model.pyi +50 -0
  28. Modeling_Tool/Eval/weighted_eval_utils.py +326 -0
  29. Modeling_Tool/Explainability/Coalition_Structure.py +305 -0
  30. Modeling_Tool/Explainability/Model_Explainer.py +743 -0
  31. Modeling_Tool/Explainability/__init__.py +24 -0
  32. Modeling_Tool/Feature/Distribution_Tool.py +509 -0
  33. Modeling_Tool/Feature/Distribution_Tool.pyi +42 -0
  34. Modeling_Tool/Feature/Feature_Insights.py +762 -0
  35. Modeling_Tool/Feature/Feature_Insights.pyi +33 -0
  36. Modeling_Tool/Feature/PSI_Tool.py +1195 -0
  37. Modeling_Tool/Feature/PSI_Tool.pyi +29 -0
  38. Modeling_Tool/Feature/WOE_Engine_Feature_Patch.py +355 -0
  39. Modeling_Tool/Feature/__init__.py +40 -0
  40. Modeling_Tool/Model/Backward_Tool.py +778 -0
  41. Modeling_Tool/Model/Backward_Tool.pyi +45 -0
  42. Modeling_Tool/Model/GBM_Search_Tool.py +251 -0
  43. Modeling_Tool/Model/GBM_Tool.py +1610 -0
  44. Modeling_Tool/Model/GBM_Tool.pyi +90 -0
  45. Modeling_Tool/Model/LRM_Tool.py +1198 -0
  46. Modeling_Tool/Model/LRM_Tool.pyi +47 -0
  47. Modeling_Tool/Model/__init__.py +61 -0
  48. Modeling_Tool/Sample/Distribution_Adaptation.py +131 -0
  49. Modeling_Tool/Sample/Distribution_Adaptation.pyi +30 -0
  50. Modeling_Tool/Sample/Reject_Infer.py +413 -0
  51. Modeling_Tool/Sample/Reject_Infer.pyi +43 -0
  52. Modeling_Tool/Sample/Sample_Split.py +520 -0
  53. Modeling_Tool/Sample/Sample_Split.pyi +43 -0
  54. Modeling_Tool/Sample/__init__.py +31 -0
  55. Modeling_Tool/UAT/UAT_Consistency_Checker.py +1180 -0
  56. Modeling_Tool/UAT/__init__.py +19 -0
  57. Modeling_Tool/WOE/WOE_Adapter.py +204 -0
  58. Modeling_Tool/WOE/WOE_Adapter.pyi +21 -0
  59. Modeling_Tool/WOE/WOE_Master.py +491 -0
  60. Modeling_Tool/WOE/WOE_Master.pyi +40 -0
  61. Modeling_Tool/WOE/WOE_Monotone_Binner.py +3324 -0
  62. Modeling_Tool/WOE/WOE_Monotone_Binner.pyi +71 -0
  63. Modeling_Tool/WOE/WOE_Plot_Tool.py +919 -0
  64. Modeling_Tool/WOE/WOE_Plot_Tool.pyi +46 -0
  65. Modeling_Tool/WOE/WOE_Report_Builder.py +214 -0
  66. Modeling_Tool/WOE/WOE_Report_Builder.pyi +24 -0
  67. Modeling_Tool/WOE/WOE_Tool.py +1094 -0
  68. Modeling_Tool/WOE/WOE_Tool.pyi +41 -0
  69. Modeling_Tool/WOE/__init__.py +86 -0
  70. Modeling_Tool/WOE/plot_woe_tool.py +290 -0
  71. Modeling_Tool/WOE/plot_woe_tool.pyi +25 -0
  72. Modeling_Tool/__init__.py +176 -0
  73. Report/Report_Tool.py +380 -0
  74. Report/__init__.py +3 -0
  75. supermodelingfactory-0.2.0.dist-info/METADATA +268 -0
  76. supermodelingfactory-0.2.0.dist-info/RECORD +79 -0
  77. supermodelingfactory-0.2.0.dist-info/WHEEL +5 -0
  78. supermodelingfactory-0.2.0.dist-info/licenses/LICENSE +102 -0
  79. supermodelingfactory-0.2.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,43 @@
1
+ # =============================================================================
2
+ # Modeling_Tool.Sample.Reject_Infer
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2026 Kyle Sun <github.com/Kyle-J-Sun>. All rights reserved.
5
+ # SuperModelingFactory — Licensed under the Business Source License 1.1.
6
+ #
7
+ # This stub describes the public API of a closed-source module compiled to a
8
+ # native extension (.so / .pyd). The original source is not distributed.
9
+ # Production / commercial use requires a separate commercial license.
10
+ #
11
+ # FINGERPRINT: SMF-REJECTINFER-31339160
12
+ # (Unique trace marker. Do not remove or alter — used for plagiarism
13
+ # detection across the public internet.)
14
+ # =============================================================================
15
+
16
+ import pandas as pd
17
+ import numpy as np
18
+ from typing import Union, Optional, List, Dict, Any, Tuple
19
+ from abc import ABC, abstractmethod
20
+
21
+ class RejectInferrer(ABC):
22
+ def __init__(self, target_col: str = 'target', score_col: str = 'score'): ...
23
+ def infer(self, df_approved: pd.DataFrame, df_rejected: pd.DataFrame, score_col: Optional[str] = None) -> pd.DataFrame: ...
24
+
25
+ class SimpleAugmentInferrer(RejectInferrer):
26
+ def __init__(self, target_col: str = 'target', score_col: str = 'score', bad_rate: Optional[float] = None): ...
27
+ def infer(self, df_approved: pd.DataFrame, df_rejected: pd.DataFrame, score_col: Optional[str] = None) -> pd.DataFrame: ...
28
+
29
+ class HardCutoffInferrer(RejectInferrer):
30
+ def __init__(self, target_col: str = 'target', score_col: str = 'score', cutoff: float = 0.5): ...
31
+ def infer(self, df_approved: pd.DataFrame, df_rejected: pd.DataFrame, score_col: Optional[str] = None) -> pd.DataFrame: ...
32
+
33
+ class FuzzyAugmentInferrer(RejectInferrer):
34
+ def __init__(self, target_col: str = 'target', score_col: str = 'score', weight_factor: float = 1.0): ...
35
+ def infer(self, df_approved: pd.DataFrame, df_rejected: pd.DataFrame, score_col: Optional[str] = None) -> pd.DataFrame: ...
36
+
37
+ class ParcelingInferrer(RejectInferrer):
38
+ def __init__(self, target_col: str = 'target', score_col: str = 'score', n_parcels: int = 10): ...
39
+ def infer(self, df_approved: pd.DataFrame, df_rejected: pd.DataFrame, score_col: Optional[str] = None) -> pd.DataFrame: ...
40
+
41
+ class RejectInferenceFactory:
42
+ def create(cls, method: str = 'parceling', **kwargs) -> RejectInferrer: ...
43
+ def available_methods(cls) -> List[str]: ...
@@ -0,0 +1,520 @@
1
+ """
2
+ Sampling classes for credit modeling.
3
+
4
+ This module provides classes for splitting samples, stratified sampling,
5
+ and sample balancing for credit model development.
6
+
7
+ Classes
8
+ -------
9
+ SampleSplitter : Split data into train/test samples.
10
+ StratifiedSampler : Stratified sampling with target balance control.
11
+ SampleBalancer : Balance samples using various techniques.
12
+
13
+ Examples
14
+ --------
15
+ >>> from Modeling_Tool_refactored.sample import SampleSplitter
16
+ >>> splitter = SampleSplitter()
17
+ >>> train, test = splitter.split(df, 'target', test_size=0.3)
18
+ """
19
+
20
+ import pandas as pd
21
+ import numpy as np
22
+ from typing import Union, Optional, List, Dict, Any, Tuple
23
+ from sklearn.model_selection import train_test_split
24
+ from Modeling_Tool.Eval.Model_Eval_Tool import PerformanceEvaluator
25
+ from Modeling_Tool.Core.utils import get_feature_names
26
+
27
+ def select_sample_seed(master_df, oot_split_col, model, tgt_name, seed_range = (3000, 3050), ins_prop = 0.7):
28
+ """ Select Best Seed for Sample Splitting. """
29
+
30
+ from tqdm import tqdm
31
+
32
+ if isinstance(model, str):
33
+ score = model
34
+
35
+ perf_res = pd.DataFrame()
36
+ for seed in tqdm(range(seed_range[0], seed_range[1])):
37
+
38
+ train_df = master_df.loc[master_df[oot_split_col].isin([1])]
39
+ oot_df = master_df.loc[master_df[oot_split_col].isin([2])]
40
+
41
+ sampler = SampleSplitter(test_size = (1 - ins_prop), random_state=seed, stratify=True)
42
+ mdl_df, val_df = sampler.split_df(train_df, tgt_name)
43
+
44
+ mdl_df['sample_ind_fnl'] = "ins"
45
+ val_df['sample_ind_fnl'] = "oos"
46
+ oot_df['sample_ind_fnl'] = "oot"
47
+
48
+ drv_w_sample_ind = pd.concat([mdl_df, val_df, oot_df])
49
+
50
+ ins_df = drv_w_sample_ind.loc[drv_w_sample_ind['sample_ind_fnl'].isin(['ins'])]
51
+ oos_df = drv_w_sample_ind.loc[drv_w_sample_ind['sample_ind_fnl'].isin(['oos'])]
52
+ oot_df = drv_w_sample_ind.loc[drv_w_sample_ind['sample_ind_fnl'].isin(['oot'])]
53
+
54
+ evaluator = PerformanceEvaluator(tgt_name=tgt_name, model=model, feature_cols=get_feature_names(model)) if not isinstance(model, str) else PerformanceEvaluator(tgt_name=tgt_name, scr_name = score)
55
+
56
+ if ins_df.shape[0] > 0:
57
+ evaluator = evaluator.add_dataset('train', ins_df)
58
+
59
+ if oos_df.shape[0] > 0:
60
+ evaluator = evaluator.add_dataset('validation', oos_df)
61
+
62
+ if oot_df.shape[0] > 0:
63
+ evaluator = evaluator.add_dataset('oot', oot_df)
64
+
65
+ result = evaluator.evaluate(to_show=False, display = False)
66
+ result['seed'] = seed
67
+
68
+ perf_res = pd.concat([perf_res, result], axis = 0)
69
+
70
+ return perf_res
71
+
72
+
73
+ class SampleSplitter:
74
+ """
75
+ Split data into training and testing samples.
76
+
77
+ This class provides flexible sample splitting with support for
78
+ stratification, random sampling, and custom split ratios.
79
+
80
+ Parameters
81
+ ----------
82
+ test_size : float, default 0.3
83
+ Proportion of data for testing (0 to 1).
84
+ random_state : int, optional
85
+ Random seed for reproducibility.
86
+ stratify : bool, default True
87
+ Whether to stratify by target variable.
88
+
89
+ Attributes
90
+ ----------
91
+ train_index_ : numpy.ndarray
92
+ Indices for training data.
93
+ test_index_ : numpy.ndarray
94
+ Indices for testing data.
95
+
96
+ Methods
97
+ -------
98
+ split(X, y, test_size=None, stratify=None)
99
+ Split data into train and test sets.
100
+ split_df(df, target, exclude_cols=None)
101
+ Split DataFrame while excluding certain columns.
102
+
103
+ Examples
104
+ --------
105
+ >>> splitter = SampleSplitter(test_size=0.2, random_state=42)
106
+ >>> train, test = splitter.split(X, y)
107
+ >>> print(f"Train size: {len(train)}, Test size: {len(test)}")
108
+ """
109
+
110
+ def __init__(self, test_size: float = 0.3,
111
+ random_state: Optional[int] = None,
112
+ stratify: bool = True):
113
+ """
114
+ Initialize SampleSplitter.
115
+
116
+ Parameters
117
+ ----------
118
+ test_size : float, default 0.3
119
+ Proportion for testing.
120
+ random_state : int, optional
121
+ Random seed.
122
+ stratify : bool, default True
123
+ Whether to stratify.
124
+ """
125
+ self.test_size = test_size
126
+ self.random_state = random_state
127
+ self.stratify = stratify
128
+ self.train_index_ = None
129
+ self.test_index_ = None
130
+
131
+ def split(self, X: Union[pd.DataFrame, np.ndarray],
132
+ y: Union[pd.Series, np.ndarray],
133
+ test_size: Optional[float] = None,
134
+ stratify: Optional[bool] = None) -> Tuple:
135
+ """
136
+ Split data into train and test sets.
137
+
138
+ Parameters
139
+ ----------
140
+ X : pandas.DataFrame or numpy.ndarray
141
+ Features.
142
+ y : pandas.Series or numpy.ndarray
143
+ Target variable.
144
+ test_size : float, optional
145
+ Override default test size.
146
+ stratify : bool, optional
147
+ Override default stratify setting.
148
+
149
+ Returns
150
+ -------
151
+ tuple
152
+ (X_train, X_test, y_train, y_test)
153
+
154
+ Examples
155
+ --------
156
+ >>> X_train, X_test, y_train, y_test = splitter.split(X, y)
157
+ """
158
+ test_size = test_size if test_size is not None else self.test_size
159
+ stratify = stratify if stratify is not None else self.stratify
160
+
161
+ y_arr = np.array(y)
162
+ stratify_param = y_arr if stratify and len(np.unique(y_arr)) > 1 else None
163
+
164
+ return train_test_split(
165
+ X, y,
166
+ test_size=test_size,
167
+ random_state=self.random_state,
168
+ stratify=stratify_param
169
+ )
170
+
171
+ def split_df(self, df: pd.DataFrame, target: str,
172
+ exclude_cols: Optional[List[str]] = None,
173
+ test_size: Optional[float] = None) -> Tuple[pd.DataFrame, pd.DataFrame]:
174
+ """
175
+ Split DataFrame while excluding certain columns from split.
176
+
177
+ Parameters
178
+ ----------
179
+ df : pandas.DataFrame
180
+ Input DataFrame.
181
+ target : str
182
+ Target column name.
183
+ exclude_cols : list of str, optional
184
+ Columns to exclude from split.
185
+ test_size : float, optional
186
+ Override default test size.
187
+
188
+ Returns
189
+ -------
190
+ tuple
191
+ (train_df, test_df)
192
+
193
+ Examples
194
+ --------
195
+ >>> train_df, test_df = splitter.split_df(df, 'target', exclude_cols=['id', 'date'])
196
+ """
197
+ test_size = test_size if test_size is not None else self.test_size
198
+
199
+ exclude_cols = exclude_cols or []
200
+ feature_cols = [c for c in df.columns if c not in exclude_cols + [target]]
201
+
202
+ X = df[feature_cols]
203
+ y = df[target]
204
+
205
+ if self.stratify:
206
+ strat = y
207
+ else:
208
+ strat = None
209
+
210
+ X_train, X_test, y_train, y_test = train_test_split(
211
+ X, y,
212
+ test_size=test_size,
213
+ random_state=self.random_state,
214
+ stratify=strat
215
+ )
216
+
217
+ train_df = X_train.copy()
218
+ train_df[target] = y_train
219
+
220
+ test_df = X_test.copy()
221
+ test_df[target] = y_test
222
+
223
+ return train_df, test_df
224
+
225
+
226
+ class StratifiedSampler:
227
+ """
228
+ Stratified sampling with target balance control.
229
+
230
+ This class provides stratified sampling that maintains
231
+ the target distribution while allowing controlled sampling.
232
+
233
+ Parameters
234
+ ----------
235
+ target_rate : float, optional
236
+ Target bad rate in the sample.
237
+ random_state : int, optional
238
+ Random seed.
239
+
240
+ Methods
241
+ -------
242
+ sample(df, target, n_samples=None, sample_frac=None)
243
+ Perform stratified sampling.
244
+ balance(df, target, method='undersample')
245
+ Balance sample by adjusting target distribution.
246
+
247
+ Examples
248
+ --------
249
+ >>> sampler = StratifiedSampler(target_rate=0.15)
250
+ >>> balanced = sampler.balance(df, 'target', method='undersample')
251
+ """
252
+
253
+ def __init__(self, target_rate: Optional[float] = None,
254
+ random_state: Optional[int] = None):
255
+ """
256
+ Initialize StratifiedSampler.
257
+ """
258
+ self.target_rate = target_rate
259
+ self.random_state = random_state
260
+ self.original_rate_ = None
261
+
262
+ def sample(self, df: pd.DataFrame, target: str,
263
+ n_samples: Optional[int] = None,
264
+ sample_frac: Optional[float] = None) -> pd.DataFrame:
265
+ """
266
+ Perform stratified sampling.
267
+
268
+ Parameters
269
+ ----------
270
+ df : pandas.DataFrame
271
+ Input data.
272
+ target : str
273
+ Target column name.
274
+ n_samples : int, optional
275
+ Number of samples to draw.
276
+ sample_frac : float, optional
277
+ Fraction of data to sample.
278
+
279
+ Returns
280
+ -------
281
+ pandas.DataFrame
282
+ Sampled DataFrame.
283
+
284
+ Examples
285
+ --------
286
+ >>> sampled = sampler.sample(df, 'target', sample_frac=0.5)
287
+ """
288
+ if sample_frac is not None:
289
+ return df.sample(frac=sample_frac, random_state=self.random_state)
290
+
291
+ if n_samples is not None:
292
+ return df.sample(n=n_samples, random_state=self.random_state)
293
+
294
+ return df.copy()
295
+
296
+ def balance(self, df: pd.DataFrame, target: str,
297
+ method: str = 'undersample') -> pd.DataFrame:
298
+ """
299
+ Balance sample by adjusting target distribution.
300
+
301
+ Parameters
302
+ ----------
303
+ df : pandas.DataFrame
304
+ Input data.
305
+ target : str
306
+ Target column name.
307
+ method : str, default 'undersample'
308
+ Balancing method: 'undersample', 'oversample', 'smote'.
309
+
310
+ Returns
311
+ -------
312
+ pandas.DataFrame
313
+ Balanced DataFrame.
314
+
315
+ Examples
316
+ --------
317
+ >>> balanced = sampler.balance(df, 'target', method='undersample')
318
+ """
319
+ self.original_rate_ = df[target].mean()
320
+
321
+ if method == 'undersample':
322
+ return self._undersample(df, target)
323
+ elif method == 'oversample':
324
+ return self._oversample(df, target)
325
+ elif method == 'smote':
326
+ return self._smote(df, target)
327
+ else:
328
+ raise ValueError(f"Unknown method: {method}")
329
+
330
+ def _undersample(self, df: pd.DataFrame, target: str) -> pd.DataFrame:
331
+ """
332
+ Undersample majority class.
333
+ """
334
+ goods = df[df[target] == 0]
335
+ bads = df[df[target] == 1]
336
+
337
+ if self.target_rate is not None:
338
+ n_bads = len(bads)
339
+ n_goods = int(n_bads * (1 - self.target_rate) / self.target_rate)
340
+ goods = goods.sample(n=min(n_goods, len(goods)), random_state=self.random_state)
341
+ else:
342
+ goods = goods.sample(n=len(bads), random_state=self.random_state)
343
+
344
+ return pd.concat([goods, bads]).sample(frac=1, random_state=self.random_state)
345
+
346
+ def _oversample(self, df: pd.DataFrame, target: str) -> pd.DataFrame:
347
+ """
348
+ Oversample minority class.
349
+ """
350
+ goods = df[df[target] == 0]
351
+ bads = df[df[target] == 1]
352
+
353
+ if len(bads) < len(goods):
354
+ if self.target_rate is not None:
355
+ n_goods = len(goods)
356
+ n_bads = int(n_goods * self.target_rate / (1 - self.target_rate))
357
+ bads = bads.sample(n=n_bads, replace=True, random_state=self.random_state)
358
+ else:
359
+ bads = bads.sample(n=len(goods), replace=True, random_state=self.random_state)
360
+
361
+ return pd.concat([goods, bads]).sample(frac=1, random_state=self.random_state)
362
+
363
+ def _smote(self, df: pd.DataFrame, target: str) -> pd.DataFrame:
364
+ """
365
+ SMOTE oversampling (requires imbalanced-learn).
366
+ """
367
+ try:
368
+ from imblearn.over_sampling import SMOTE
369
+ except ImportError:
370
+ raise ImportError("imbalanced-learn required for SMOTE. Install with: pip install imbalanced-learn")
371
+
372
+ goods = df[df[target] == 0]
373
+ bads = df[df[target] == 1]
374
+
375
+ if len(bads) < 6:
376
+ return self._oversample(df, target)
377
+
378
+ X_cols = [c for c in df.columns if c != target]
379
+ X = df[X_cols].values
380
+ y = df[target].values
381
+
382
+ smote = SMOTE(random_state=self.random_state)
383
+ X_resampled, y_resampled = smote.fit_resample(X, y)
384
+
385
+ return pd.DataFrame(X_resampled, columns=X_cols).assign(**{target: y_resampled})
386
+
387
+
388
+ class SampleBalancer:
389
+ """
390
+ Advanced sample balancing with multiple methods.
391
+
392
+ This class provides various sampling techniques to handle
393
+ class imbalance in credit modeling.
394
+
395
+ Parameters
396
+ ----------
397
+ method : str, default 'random'
398
+ Balancing method.
399
+ target_ratio : float, optional
400
+ Desired minority/majority ratio.
401
+ random_state : int, optional
402
+ Random seed.
403
+
404
+ Methods
405
+ -------
406
+ fit_resample(X, y)
407
+ Resample features and target.
408
+ get_balanced_indices(y)
409
+ Get indices for balanced sampling.
410
+
411
+ Examples
412
+ --------
413
+ >>> balancer = SampleBalancer(method='nearmiss')
414
+ >>> X_bal, y_bal = balancer.fit_resample(X, y)
415
+ """
416
+
417
+ def __init__(self, method: str = 'random',
418
+ target_ratio: Optional[float] = None,
419
+ random_state: Optional[int] = None):
420
+ """
421
+ Initialize SampleBalancer.
422
+ """
423
+ self.method = method
424
+ self.target_ratio = target_ratio
425
+ self.random_state = random_state
426
+
427
+ def fit_resample(self, X: Union[pd.DataFrame, np.ndarray],
428
+ y: Union[pd.Series, np.ndarray]) -> Tuple:
429
+ """
430
+ Resample data to balance classes.
431
+
432
+ Parameters
433
+ ----------
434
+ X : pandas.DataFrame or numpy.ndarray
435
+ Features.
436
+ y : pandas.Series or numpy.ndarray
437
+ Target.
438
+
439
+ Returns
440
+ -------
441
+ tuple
442
+ (X_resampled, y_resampled)
443
+
444
+ Examples
445
+ --------
446
+ >>> X_bal, y_bal = balancer.fit_resample(X, y)
447
+ """
448
+ if self.method == 'random':
449
+ return self._random_undersample(X, y)
450
+ elif self.method == 'nearmiss':
451
+ return self._nearmiss(X, y)
452
+ elif self.method == 'tomek':
453
+ return self._tomek_links(X, y)
454
+ elif self.method == 'enn':
455
+ return self._edited_nn(X, y)
456
+ else:
457
+ raise ValueError(f"Unknown method: {self.method}")
458
+
459
+ def _random_undersample(self, X, y):
460
+ """
461
+ Random undersampling.
462
+ """
463
+ goods = y == 0
464
+ bads = y == 1
465
+
466
+ n_bads = goods.sum() if self.target_ratio else bads.sum()
467
+
468
+ if self.target_ratio:
469
+ n_goods = int(n_bads * (1 - self.target_ratio) / self.target_ratio)
470
+ else:
471
+ n_goods = n_bads
472
+
473
+ goods_indices = np.where(goods)[0]
474
+ bads_indices = np.where(bads)[0]
475
+
476
+ np.random.seed(self.random_state)
477
+ goods_sample = np.random.choice(goods_indices, size=n_goods, replace=False)
478
+
479
+ selected = np.concatenate([goods_sample, bads_indices])
480
+ np.random.shuffle(selected)
481
+
482
+ if isinstance(X, pd.DataFrame):
483
+ return X.iloc[selected].copy(), y.iloc[selected].copy()
484
+ return X[selected], y[selected]
485
+
486
+ def _nearmiss(self, X, y):
487
+ """
488
+ NearMiss undersampling.
489
+ """
490
+ try:
491
+ from imblearn.under_sampling import NearMiss
492
+ except ImportError:
493
+ raise ImportError("imbalanced-learn required. Install with: pip install imbalanced-learn")
494
+
495
+ nm = NearMiss(version=1, random_state=self.random_state)
496
+ return nm.fit_resample(X, y)
497
+
498
+ def _tomek_links(self, X, y):
499
+ """
500
+ Tomek links cleaning.
501
+ """
502
+ try:
503
+ from imblearn.under_sampling import TomekLinks
504
+ except ImportError:
505
+ raise ImportError("imbalanced-learn required. Install with: pip install imbalanced-learn")
506
+
507
+ tl = TomekLinks(random_state=self.random_state)
508
+ return tl.fit_resample(X, y)
509
+
510
+ def _edited_nn(self, X, y):
511
+ """
512
+ Edited Nearest Neighbors cleaning.
513
+ """
514
+ try:
515
+ from imblearn.under_sampling import EditedNearestNeighbours
516
+ except ImportError:
517
+ raise ImportError("imbalanced-learn required. Install with: pip install imbalanced-learn")
518
+
519
+ enn = EditedNearestNeighbours(random_state=self.random_state)
520
+ return enn.fit_resample(X, y)
@@ -0,0 +1,43 @@
1
+ # =============================================================================
2
+ # Modeling_Tool.Sample.Sample_Split
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2026 Kyle Sun <github.com/Kyle-J-Sun>. All rights reserved.
5
+ # SuperModelingFactory — Licensed under the Business Source License 1.1.
6
+ #
7
+ # This stub describes the public API of a closed-source module compiled to a
8
+ # native extension (.so / .pyd). The original source is not distributed.
9
+ # Production / commercial use requires a separate commercial license.
10
+ #
11
+ # FINGERPRINT: SMF-SAMPLESPLIT-aeab7413
12
+ # (Unique trace marker. Do not remove or alter — used for plagiarism
13
+ # detection across the public internet.)
14
+ # =============================================================================
15
+
16
+ import pandas as pd
17
+ import numpy as np
18
+ from typing import Union, Optional, List, Dict, Any, Tuple
19
+ from sklearn.model_selection import train_test_split
20
+ from Modeling_Tool.Eval.Model_Eval_Tool import PerformanceEvaluator
21
+ from Modeling_Tool.Core.utils import get_feature_names
22
+ def select_sample_seed(master_df, oot_split_col, model, tgt_name, seed_range = (3000, 3050), ins_prop = 0.7): ...
23
+
24
+ class SampleSplitter:
25
+ def __init__(self, test_size: float = 0.3, random_state: Optional[int] = None, stratify: bool = True): ...
26
+ def split(self, X: Union[pd.DataFrame, np.ndarray], y: Union[pd.Series, np.ndarray], test_size: Optional[float] = None, stratify: Optional[bool] = None) -> Tuple: ...
27
+ def split_df(self, df: pd.DataFrame, target: str, exclude_cols: Optional[List[str]] = None, test_size: Optional[float] = None) -> Tuple[pd.DataFrame, pd.DataFrame]: ...
28
+
29
+ class StratifiedSampler:
30
+ def __init__(self, target_rate: Optional[float] = None, random_state: Optional[int] = None): ...
31
+ def sample(self, df: pd.DataFrame, target: str, n_samples: Optional[int] = None, sample_frac: Optional[float] = None) -> pd.DataFrame: ...
32
+ def balance(self, df: pd.DataFrame, target: str, method: str = 'undersample') -> pd.DataFrame: ...
33
+ def _undersample(self, df: pd.DataFrame, target: str) -> pd.DataFrame: ...
34
+ def _oversample(self, df: pd.DataFrame, target: str) -> pd.DataFrame: ...
35
+ def _smote(self, df: pd.DataFrame, target: str) -> pd.DataFrame: ...
36
+
37
+ class SampleBalancer:
38
+ def __init__(self, method: str = 'random', target_ratio: Optional[float] = None, random_state: Optional[int] = None): ...
39
+ def fit_resample(self, X: Union[pd.DataFrame, np.ndarray], y: Union[pd.Series, np.ndarray]) -> Tuple: ...
40
+ def _random_undersample(self, X, y): ...
41
+ def _nearmiss(self, X, y): ...
42
+ def _tomek_links(self, X, y): ...
43
+ def _edited_nn(self, X, y): ...
@@ -0,0 +1,31 @@
1
+ from .Distribution_Adaptation import DistributionAdaptation
2
+
3
+ from .Reject_Infer import (
4
+ RejectInferrer,
5
+ SimpleAugmentInferrer,
6
+ HardCutoffInferrer,
7
+ FuzzyAugmentInferrer,
8
+ ParcelingInferrer,
9
+ RejectInferenceFactory,
10
+ )
11
+
12
+ from .Sample_Split import (
13
+ SampleSplitter,
14
+ StratifiedSampler,
15
+ SampleBalancer,
16
+ select_sample_seed,
17
+ )
18
+
19
+
20
+ __all__ = [
21
+ # Distribution_Adaptation
22
+ 'DistributionAdaptation',
23
+
24
+ # Reject_Infer
25
+ 'RejectInferrer', 'SimpleAugmentInferrer', 'HardCutoffInferrer',
26
+ 'FuzzyAugmentInferrer', 'ParcelingInferrer', 'RejectInferenceFactory',
27
+
28
+ # Sample_Split
29
+ 'SampleSplitter', 'StratifiedSampler', 'SampleBalancer',
30
+ 'select_sample_seed',
31
+ ]