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,99 @@
1
+ from .Binning_Tool import (
2
+ Binning,
3
+ chi2_binning,
4
+ run_binning,
5
+ super_binning,
6
+ get_max_nbins,
7
+ get_decision_tree_binning_edges,
8
+ NumVarBinning,
9
+ cre_pvt,
10
+ merge_bins,
11
+ observed_laplace,
12
+ cat_2_list,
13
+ get_bin_range,
14
+ get_bin_range_list,
15
+ chi2_auto_binning,
16
+ quick_binning,
17
+ )
18
+
19
+ def __getattr__(name):
20
+ if name == "ODPSRunner":
21
+ from .ODPS_Tool import ODPSRunner as _ODPSRunner
22
+ return _ODPSRunner
23
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
24
+
25
+ from .Slope_Tool import (
26
+ calculate_slope_sklearn,
27
+ calculate_slope_scipy,
28
+ calculate_slope_numpy,
29
+ calculate_slope_manual,
30
+ SlopeCalculator,
31
+ )
32
+
33
+ from .sample_weight_utils import (
34
+ resolve_sample_weight,
35
+ validate_sample_weight,
36
+ weighted_sum,
37
+ weighted_mean,
38
+ weighted_rate,
39
+ )
40
+
41
+ from .utils import (
42
+ cut2pieces,
43
+ proc_freq,
44
+ read_attr_list,
45
+ write_attr_list,
46
+ odds_score,
47
+ parse_odps_schema,
48
+ npnan2none,
49
+ drop_tmp_cols,
50
+ mkdir_if_not_exist,
51
+ parse_sql_file,
52
+ calc_woe,
53
+ calc_iv,
54
+ scoring,
55
+ get_missing_indicator,
56
+ upload_score,
57
+ DataFrameProcessor,
58
+ FilePathManager,
59
+ DateTimeUtils,
60
+ WOEIVCalculator,
61
+ get_feature_names,
62
+ get_feature_names_lgb,
63
+ get_feature_names_xgb,
64
+ get_feature_names_batch,
65
+ pull_attributes_in_batch,
66
+ )
67
+ from .Model_Registry_Tool import (
68
+ make_model_artifact,
69
+ save_model,
70
+ load_model,
71
+ load_model_metadata,
72
+ )
73
+
74
+ from .XOR_Encryptor import TextEncryptor
75
+
76
+ from .kDataFrame import kSeries, kDataFrame
77
+
78
+ __all__ = [
79
+ 'Binning', 'chi2_binning', 'run_binning', 'super_binning',
80
+ 'get_max_nbins', 'get_decision_tree_binning_edges', 'NumVarBinning',
81
+ 'cre_pvt', 'merge_bins', 'observed_laplace', 'cat_2_list',
82
+ 'get_bin_range', 'get_bin_range_list', 'chi2_auto_binning', 'quick_binning',
83
+ 'ODPSRunner',
84
+ 'calculate_slope_sklearn', 'calculate_slope_scipy',
85
+ 'calculate_slope_numpy', 'calculate_slope_manual',
86
+ 'SlopeCalculator',
87
+ 'resolve_sample_weight', 'validate_sample_weight',
88
+ 'weighted_sum', 'weighted_mean', 'weighted_rate',
89
+ 'cut2pieces', 'proc_freq', 'read_attr_list', 'write_attr_list',
90
+ 'odds_score', 'parse_odps_schema', 'npnan2none', 'drop_tmp_cols',
91
+ 'mkdir_if_not_exist', 'parse_sql_file', 'calc_woe', 'calc_iv',
92
+ 'save_model', 'load_model', 'load_model_metadata', 'make_model_artifact',
93
+ 'scoring', 'get_missing_indicator', 'upload_score',
94
+ 'get_feature_names', 'get_feature_names_lgb', 'get_feature_names_xgb',
95
+ 'get_feature_names_batch', 'pull_attributes_in_batch',
96
+ 'DataFrameProcessor', 'FilePathManager', 'DateTimeUtils', 'WOEIVCalculator',
97
+ 'TextEncryptor',
98
+ 'kSeries', 'kDataFrame',
99
+ ]
@@ -0,0 +1,228 @@
1
+ import logging
2
+
3
+ import pandas as pd
4
+ from pandas import DataFrame
5
+ from pandas import Series
6
+ import numpy as np
7
+
8
+ # Available only in newer pandas versions. Older Airflow images should skip it.
9
+ try:
10
+ pd.set_option('future.no_silent_downcasting', True)
11
+ except (KeyError, ValueError):
12
+ pass
13
+ pd.options.mode.chained_assignment = None # default='warn'
14
+
15
+ logging.basicConfig(level=logging.INFO, format="%(message)s")
16
+
17
+ class kSeries(Series):
18
+ @property
19
+ def _constructor(self):
20
+ return kSeries
21
+
22
+ @property
23
+ def _constructor_expanddim(self):
24
+ return kDataFrame
25
+
26
+ def __init__(self, data, *args, **kwargs):
27
+ super().__init__(data, *args, **kwargs)
28
+
29
+ def to_pdSeries(self, inplace: bool = False):
30
+ """
31
+ Convert kSeries back to pandas Series.
32
+ """
33
+ if inplace:
34
+ data = self
35
+ else:
36
+ data = self.copy()
37
+
38
+ df = Series(data)
39
+ return df
40
+
41
+ def odds_score(self):
42
+ """
43
+ Calculate the odd score based on the given probability score.
44
+
45
+ Odds Score = (count of sth happening) / (count of sth not happening)
46
+ Odds Score = pb_score / (1-pb_score) [This ranges from 0 to infinity.]
47
+ Log Odds Score = np.log(pb_score / (1-pb_score)) [This ranges from -infinity to +infinity]
48
+ This is helpful for solving binary classification problem.
49
+ Odds Ratio: The ratio of odds.
50
+ """
51
+ pb_score = self
52
+ a = (20 / np.log(2))
53
+ b = (np.log(15) + np.log(pb_score/(1 - pb_score)))
54
+ return (500 - a * b)
55
+
56
+ def scale_score(self):
57
+ """
58
+ Scale the model scores (for internt segment of MCI model)
59
+ """
60
+ data = self.copy()
61
+ def app_func(x):
62
+ scores = x * 1.112
63
+ if (scores > 0.9999999):
64
+ return 0.9999999
65
+ return scores
66
+ return data.apply(app_func)
67
+
68
+ def proc_freq(self) -> pd.DataFrame:
69
+ """
70
+ Implement the Python version "proc freq" query in SAS.
71
+ """
72
+ data = self.copy()
73
+ f = data.value_counts(dropna = False)
74
+ p = data.value_counts(dropna = False, normalize = True)
75
+ df = pd.concat([f,p], axis = 1, keys = ['frequency', 'percent'])
76
+ df['cumFrequency'] = df['frequency'].cumsum()
77
+ df['cumPercent'] = df['percent'].cumsum()
78
+ return df
79
+
80
+
81
+
82
+ class kDataFrame(DataFrame):
83
+ """
84
+ The extension class of Pandas DataFrame including more useful methods to manipulate dataset.
85
+
86
+ Parameters:
87
+ -----------
88
+ data [DataFrame]: Any pandas dataframe dataset.
89
+
90
+ Return:
91
+ -------
92
+ data [kDataFrame]: the extension object of dataframe.
93
+
94
+ """
95
+ _metadata = ['added_property']
96
+ added_property = 1 # This will be passed to copies
97
+
98
+ @property
99
+ def _constructor(self):
100
+ return kDataFrame
101
+
102
+ @property
103
+ def _constructor_sliced(self):
104
+ return kSeries
105
+
106
+ def __init__(self, data, *args, **kwargs):
107
+ super().__init__(data, *args, **kwargs)
108
+
109
+ def move_column(self, colname: str, idx: int, inplace: bool = False):
110
+ """
111
+ To move a column into specific place by index.
112
+ """
113
+ if inplace:
114
+ data = self
115
+ else:
116
+ data = self.copy()
117
+ colarray = data.columns.tolist()
118
+ colarray.remove(colname)
119
+ colarray.insert(idx, colname)
120
+ data = data[colarray]
121
+ return data
122
+
123
+ def convert_to_vintage(self, vintage_colname: str = 'VINTAGE', by: str = 'TRAN_TMS', inplace: bool = False):
124
+ """
125
+ To obtain a vintage column by a time/data column.
126
+ """
127
+ if inplace:
128
+ data = self
129
+ else:
130
+ data = self.copy()
131
+ import re
132
+ data[vintage_colname] = data[by].apply(lambda x: re.search("\d{4}-\d{2}", x).group().replace('-', ''))
133
+ if inplace:
134
+ self = data
135
+ return data
136
+
137
+ def col_filter_regex(self, regex: str = ".*?of_co_at_12m", case_sensitive = True, inplace: bool = False):
138
+ """
139
+ To filter the DataFrame columns by regular expression.
140
+ """
141
+ if inplace:
142
+ data = self
143
+ else:
144
+ data = self.copy()
145
+
146
+ fltr = data.columns[data.columns.str.contains(regex, regex = True, case = case_sensitive)]
147
+ return data[fltr]
148
+
149
+ def row_filter_regex(self, col = None, regex: str = None, case_sensitive = True,
150
+ as_index = False, inplace: bool = False):
151
+ """
152
+ To filter the string format row using regex.
153
+ """
154
+ if inplace:
155
+ data = self
156
+ else:
157
+ data = self.copy()
158
+
159
+ fltr = data[col].astype('str').str.contains(pat = regex, regex = True, case = case_sensitive)
160
+ if as_index:
161
+ return data[fltr].set_index(col)
162
+ return data[fltr]
163
+
164
+ def scale_score(self, pb_score: str):
165
+ """
166
+ Scale the model scores (for internt segment of MCI model)
167
+ """
168
+ data = self.copy()
169
+ def app_func(x):
170
+ scores = x * 1.112
171
+ if (scores > 0.9999999):
172
+ return 0.9999999
173
+ return scores
174
+ return data[pb_score].apply(app_func)
175
+
176
+ def proc_freq(self, var: str):
177
+ """
178
+ Implement the Python version "proc freq" query in SAS.
179
+ """
180
+ data = self.copy()
181
+ f = data[var].value_counts(dropna = False)
182
+ p = data[var].value_counts(dropna = False, normalize = True)
183
+ df = pd.concat([f,p], axis = 1, keys = ['frequency', 'percent'])
184
+ df['cumFrequency'] = df['frequency'].cumsum()
185
+ df['cumPercent'] = df['percent'].cumsum()
186
+ return df
187
+
188
+ def unify_table_col_names(self, how: str = "lowercase", inplace: bool = False):
189
+ """
190
+ Unify the format of column names.
191
+ """
192
+
193
+ if inplace:
194
+ data = self
195
+ else:
196
+ data = self.copy()
197
+
198
+ cols = data.columns
199
+ if how.lower() == "lower" or how.lower() == "lowercase":
200
+ res = [name.lower() for name in cols]
201
+ if how.lower() == "upper" or how.lower() == "uppercase":
202
+ res = [name.upper() for name in cols]
203
+ if how.lower() == "cap" or how.lower() == "capitalize":
204
+ res = [name.capitalize() for name in cols]
205
+ data.columns = res
206
+ return data
207
+
208
+ def convert_strlist_to_list(self, col: str):
209
+ """
210
+ cast string-type lists in a specified Series into real lists.
211
+ """
212
+ import re
213
+
214
+ data = self.copy()
215
+ str_col = kSeries([re.findall("\w+", str(x)) for x in data[col]])
216
+ return str_col
217
+
218
+ def to_pdDataFrame(self, inplace: bool = False):
219
+ """
220
+ Convert df_extension back to DataFrame.
221
+ """
222
+ if inplace:
223
+ data = self
224
+ else:
225
+ data = self.copy()
226
+
227
+ df = DataFrame(data)
228
+ return df
@@ -0,0 +1,43 @@
1
+ # =============================================================================
2
+ # Modeling_Tool.Core.kDataFrame
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-KDATAFRAME-76c89511
12
+ # (Unique trace marker. Do not remove or alter — used for plagiarism
13
+ # detection across the public internet.)
14
+ # =============================================================================
15
+
16
+ import logging
17
+ import pandas as pd
18
+ from pandas import DataFrame
19
+ from pandas import Series
20
+ import numpy as np
21
+
22
+ class kSeries(Series):
23
+ def _constructor(self): ...
24
+ def _constructor_expanddim(self): ...
25
+ def __init__(self, data, *args, **kwargs): ...
26
+ def to_pdSeries(self, inplace: bool = False): ...
27
+ def odds_score(self): ...
28
+ def scale_score(self): ...
29
+ def proc_freq(self) -> pd.DataFrame: ...
30
+
31
+ class kDataFrame(DataFrame):
32
+ def _constructor(self): ...
33
+ def _constructor_sliced(self): ...
34
+ def __init__(self, data, *args, **kwargs): ...
35
+ def move_column(self, colname: str, idx: int, inplace: bool = False): ...
36
+ def convert_to_vintage(self, vintage_colname: str = 'VINTAGE', by: str = 'TRAN_TMS', inplace: bool = False): ...
37
+ def col_filter_regex(self, regex: str = '.*?of_co_at_12m', case_sensitive = True, inplace: bool = False): ...
38
+ def row_filter_regex(self, col = None, regex: str = None, case_sensitive = True, as_index = False, inplace: bool = False): ...
39
+ def scale_score(self, pb_score: str): ...
40
+ def proc_freq(self, var: str): ...
41
+ def unify_table_col_names(self, how: str = 'lowercase', inplace: bool = False): ...
42
+ def convert_strlist_to_list(self, col: str): ...
43
+ def to_pdDataFrame(self, inplace: bool = False): ...
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ """Sample-weight resolution and weighted aggregation helpers."""
3
+ from __future__ import annotations
4
+
5
+ import numpy as np
6
+
7
+
8
+ def resolve_sample_weight(
9
+ data=None,
10
+ weight_col=None,
11
+ sample_weight=None,
12
+ expected_len=None,
13
+ wgt=None,
14
+ wgt_col=None,
15
+ ):
16
+ """Resolve sample weights from a DataFrame column or array.
17
+
18
+ Accepts ``weight_col`` / ``wgt_col`` and ``sample_weight`` / ``wgt`` aliases.
19
+ Returns ``None`` when no weight source is provided.
20
+ """
21
+ if weight_col is None:
22
+ weight_col = wgt_col
23
+ if sample_weight is None:
24
+ sample_weight = wgt
25
+
26
+ if sample_weight is not None and weight_col is not None:
27
+ raise ValueError("Provide either weight_col or sample_weight, not both.")
28
+
29
+ if weight_col is not None:
30
+ if data is None:
31
+ raise ValueError("data is required when weight_col is provided.")
32
+ if weight_col not in data.columns:
33
+ raise KeyError("weight column '{0}' not found in data".format(weight_col))
34
+ sample_weight = data[weight_col].values
35
+
36
+ if sample_weight is None:
37
+ return None
38
+
39
+ return validate_sample_weight(sample_weight, expected_len=expected_len)
40
+
41
+
42
+ def validate_sample_weight(weights, expected_len=None):
43
+ """Validate and return a 1-D float numpy weight vector."""
44
+ w = np.asarray(weights, dtype=float)
45
+ if w.ndim != 1:
46
+ raise ValueError("sample_weight must be 1-dimensional.")
47
+ if expected_len is not None and len(w) != expected_len:
48
+ raise ValueError(
49
+ "sample_weight length {0} != expected {1}".format(len(w), expected_len)
50
+ )
51
+ if not np.all(np.isfinite(w)):
52
+ raise ValueError("sample_weight must be finite (no NaN/inf).")
53
+ if np.any(w < 0):
54
+ raise ValueError("sample_weight must be non-negative.")
55
+ return w
56
+
57
+
58
+ def weighted_sum(values, weights):
59
+ """Weighted sum of values."""
60
+ v = np.asarray(values, dtype=float)
61
+ w = np.asarray(weights, dtype=float)
62
+ return float(np.sum(v * w))
63
+
64
+
65
+ def weighted_mean(values, weights):
66
+ """Weighted mean; returns NaN when total weight is zero."""
67
+ w = np.asarray(weights, dtype=float)
68
+ total = float(np.sum(w))
69
+ if total == 0:
70
+ return np.nan
71
+ return weighted_sum(values, weights) / total
72
+
73
+
74
+ def weighted_rate(mask, weights):
75
+ """Weighted rate of True / 1 values in mask."""
76
+ m = np.asarray(mask, dtype=float)
77
+ return weighted_mean(m, weights)