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,19 @@
1
+ from .UAT_Consistency_Checker import (
2
+ UATConfig,
3
+ UATConsistencyChecker,
4
+ safe_diff,
5
+ safe_eq,
6
+ mismatch_mask,
7
+ time_diff_seconds,
8
+ time_mismatch_mask,
9
+ )
10
+
11
+ __all__ = [
12
+ 'UATConfig',
13
+ 'UATConsistencyChecker',
14
+ 'safe_diff',
15
+ 'safe_eq',
16
+ 'mismatch_mask',
17
+ 'time_diff_seconds',
18
+ 'time_mismatch_mask',
19
+ ]
@@ -0,0 +1,204 @@
1
+ """Unified adapters for WOE binning engines.
2
+
3
+ The public toolkit has two WOE engines with different persistence formats:
4
+ ``WOE_Master`` exposes a mapping table, while ``MonotoneWOEBinner`` exposes
5
+ ``get_final_bins`` and ``apply_woe``. This module gives feature screening and
6
+ monitoring tools one small protocol to depend on instead of branching on each
7
+ engine implementation. The adapter is intentionally read-only with respect to
8
+ fitting: callers fit the engine once, then reuse it downstream.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from typing import Any, Iterable, Optional
15
+
16
+ import numpy as np
17
+ import pandas as pd
18
+
19
+
20
+ _CANONICAL_COLUMNS = [
21
+ "VAR",
22
+ "BIN_NUM",
23
+ "BIN_RANGE",
24
+ "MIN",
25
+ "MAX",
26
+ "N",
27
+ "N_BAD",
28
+ "N_GOOD",
29
+ "AVG_BAD",
30
+ "WOE",
31
+ "IV",
32
+ "IS_SPECIAL",
33
+ "ENGINE",
34
+ ]
35
+
36
+
37
+ def _upper_columns(df: pd.DataFrame) -> pd.DataFrame:
38
+ out = df.copy()
39
+ out.columns = [str(c).upper() for c in out.columns]
40
+ return out
41
+
42
+
43
+ def _first_existing(df: pd.DataFrame, names: Iterable[str]) -> Optional[str]:
44
+ cols = set(df.columns)
45
+ for name in names:
46
+ if name in cols:
47
+ return name
48
+ return None
49
+
50
+
51
+ def _coerce_woe_frame(df: pd.DataFrame, var: Optional[str], engine: str) -> pd.DataFrame:
52
+ """Normalize a single engine WOE table to the common column contract."""
53
+ if df is None or len(df) == 0:
54
+ return pd.DataFrame(columns=_CANONICAL_COLUMNS)
55
+
56
+ src = _upper_columns(pd.DataFrame(df))
57
+ out = pd.DataFrame(index=src.index)
58
+
59
+ var_col = _first_existing(src, ["VAR", "VARIABLE", "FEATURE", "FEATURE_NAME", "ATTRIBUTE"])
60
+ out["VAR"] = src[var_col] if var_col else var
61
+
62
+ bin_col = _first_existing(src, ["BIN_NUM", "BIN", "BIN_ID", "GROUP", "IDX"])
63
+ out["BIN_NUM"] = src[bin_col] if bin_col else np.arange(1, len(src) + 1)
64
+
65
+ range_col = _first_existing(src, ["BIN_RANGE", "RANGE", "BIN_LABEL", "LABEL", "CATEGORY", "CATE", "VALUE"])
66
+ out["BIN_RANGE"] = src[range_col] if range_col else out["BIN_NUM"].astype(str)
67
+
68
+ for target, candidates in {
69
+ "MIN": ["MIN", "LEFT", "LOWER", "LOWER_BOUND", "START"],
70
+ "MAX": ["MAX", "RIGHT", "UPPER", "UPPER_BOUND", "END"],
71
+ "N": ["N", "COUNT", "TOTAL", "TOTAL_COUNT", "CNT"],
72
+ "N_BAD": ["N_BAD", "BAD", "BAD_COUNT", "TARGET", "TARGET_COUNT"],
73
+ "N_GOOD": ["N_GOOD", "GOOD", "GOOD_COUNT", "NON_TARGET", "NON_TARGET_COUNT"],
74
+ "AVG_BAD": ["AVG_BAD", "BAD_RATE", "BADRATE", "TARGET_RATE", "EVENT_RATE"],
75
+ "WOE": ["WOE", "WOE_VALUE"],
76
+ "IV": ["IV", "IV_VALUE"],
77
+ }.items():
78
+ col = _first_existing(src, candidates)
79
+ out[target] = src[col] if col else np.nan
80
+
81
+ special_col = _first_existing(src, ["IS_SPECIAL", "SPECIAL", "SPECIAL_BIN"])
82
+ if special_col:
83
+ out["IS_SPECIAL"] = src[special_col].astype(bool)
84
+ else:
85
+ out["IS_SPECIAL"] = out["BIN_RANGE"].astype(str).str.lower().str.contains("special|missing|nan")
86
+
87
+ out["ENGINE"] = engine
88
+ return out[_CANONICAL_COLUMNS]
89
+
90
+
91
+ @dataclass
92
+ class WOEEngineAdapter:
93
+ """Small protocol wrapper used by Feature and monitoring tools."""
94
+
95
+ engine: Any
96
+ engine_name: str
97
+ woe_suffix: str = "_woe"
98
+
99
+ def transform(self, data: pd.DataFrame, varlist: Optional[list[str]] = None, suffix: str = "_woe") -> pd.DataFrame:
100
+ raise NotImplementedError
101
+
102
+ def assign_bins(self, data: pd.DataFrame, var: str) -> pd.Series:
103
+ """Return stable bin labels for PSI-like distribution comparisons.
104
+
105
+ For both engines, the WOE value is a stable fitted-bin proxy. This keeps
106
+ the method independent from each engine's private bin-label internals.
107
+ """
108
+ transformed = self.transform(data, [var], suffix=self.woe_suffix)
109
+ woe_col = f"{var}{self.woe_suffix}"
110
+ if woe_col not in transformed.columns:
111
+ raise KeyError(f"WOE column {woe_col!r} was not produced by {self.engine_name}")
112
+ return transformed[woe_col].map(lambda x: "__MISSING__" if pd.isna(x) else str(x))
113
+
114
+ def get_woe_table(self, varlist: Optional[list[str]] = None) -> pd.DataFrame:
115
+ raise NotImplementedError
116
+
117
+ def get_bin_edges(self, varlist: Optional[list[str]] = None) -> dict[str, list[float]]:
118
+ return {}
119
+
120
+ def get_engine_name(self) -> str:
121
+ return self.engine_name
122
+
123
+
124
+ class WOEMasterAdapter(WOEEngineAdapter):
125
+ def __init__(self, engine: Any, woe_suffix: str = "_woe"):
126
+ super().__init__(engine=engine, engine_name="master", woe_suffix=woe_suffix)
127
+
128
+ def transform(self, data: pd.DataFrame, varlist: Optional[list[str]] = None, suffix: str = "_woe") -> pd.DataFrame:
129
+ try:
130
+ return self.engine.transform(data=data, varlist=varlist)
131
+ except TypeError:
132
+ return self.engine.transform(data, varlist)
133
+
134
+ def get_woe_table(self, varlist: Optional[list[str]] = None) -> pd.DataFrame:
135
+ table = self.engine.get_mapping_table()
136
+ out = _coerce_woe_frame(table, None, self.engine_name)
137
+ if varlist is not None:
138
+ out = out[out["VAR"].isin(varlist)]
139
+ return out.reset_index(drop=True)
140
+
141
+
142
+ class MonotoneBinnerAdapter(WOEEngineAdapter):
143
+ def __init__(self, engine: Any, woe_suffix: str = "_woe"):
144
+ super().__init__(engine=engine, engine_name="monotone", woe_suffix=woe_suffix)
145
+
146
+ def transform(self, data: pd.DataFrame, varlist: Optional[list[str]] = None, suffix: str = "_woe") -> pd.DataFrame:
147
+ transformed = self.engine.apply_woe(data, suffix=suffix, inplace=False)
148
+ if varlist is None:
149
+ return transformed
150
+ keep = list(data.columns) + [f"{v}{suffix}" for v in varlist if f"{v}{suffix}" in transformed.columns]
151
+ return transformed.loc[:, list(dict.fromkeys([c for c in keep if c in transformed.columns]))]
152
+
153
+ def get_woe_table(self, varlist: Optional[list[str]] = None) -> pd.DataFrame:
154
+ bins = self.engine.get_final_bins()
155
+ frames = []
156
+ selected = set(varlist) if varlist is not None else None
157
+ for var, df in bins.items():
158
+ if selected is not None and var not in selected:
159
+ continue
160
+ frames.append(_coerce_woe_frame(df, var, self.engine_name))
161
+ if not frames:
162
+ return pd.DataFrame(columns=_CANONICAL_COLUMNS)
163
+ return pd.concat(frames, ignore_index=True)[_CANONICAL_COLUMNS]
164
+
165
+ def get_bin_edges(self, varlist: Optional[list[str]] = None) -> dict[str, list[float]]:
166
+ if not hasattr(self.engine, "get_bin_edges"):
167
+ return {}
168
+ edges = self.engine.get_bin_edges()
169
+ if varlist is None:
170
+ return edges
171
+ return {k: v for k, v in edges.items() if k in set(varlist)}
172
+
173
+
174
+ def as_woe_engine(engine: Any, woe_suffix: str = "_woe") -> Optional[WOEEngineAdapter]:
175
+ """Return a unified adapter for supported fitted WOE engines.
176
+
177
+ Parameters
178
+ ----------
179
+ engine:
180
+ ``WOE_Master``, ``MonotoneWOEBinner`` or an existing adapter. ``None`` is
181
+ returned unchanged so callers can preserve legacy behavior.
182
+ woe_suffix:
183
+ Suffix used for generated WOE columns.
184
+ """
185
+ if engine is None:
186
+ return None
187
+ if isinstance(engine, WOEEngineAdapter):
188
+ return engine
189
+ if hasattr(engine, "get_mapping_table") and hasattr(engine, "transform"):
190
+ return WOEMasterAdapter(engine, woe_suffix=woe_suffix)
191
+ if hasattr(engine, "get_final_bins") and hasattr(engine, "apply_woe"):
192
+ return MonotoneBinnerAdapter(engine, woe_suffix=woe_suffix)
193
+ raise TypeError(
194
+ "Unsupported WOE engine. Expected WOE_Master, MonotoneWOEBinner, "
195
+ "or WOEEngineAdapter."
196
+ )
197
+
198
+
199
+ __all__ = [
200
+ "WOEEngineAdapter",
201
+ "WOEMasterAdapter",
202
+ "MonotoneBinnerAdapter",
203
+ "as_woe_engine",
204
+ ]
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Optional
3
+ import pandas as pd
4
+
5
+ class WOEEngineAdapter:
6
+ engine: Any
7
+ engine_name: str
8
+ woe_suffix: str
9
+ def transform(self, data: pd.DataFrame, varlist: Optional[list[str]] = None, suffix: str = '_woe') -> pd.DataFrame: ...
10
+ def assign_bins(self, data: pd.DataFrame, var: str) -> pd.Series: ...
11
+ def get_woe_table(self, varlist: Optional[list[str]] = None) -> pd.DataFrame: ...
12
+ def get_bin_edges(self, varlist: Optional[list[str]] = None) -> dict[str, list[float]]: ...
13
+ def get_engine_name(self) -> str: ...
14
+
15
+ class WOEMasterAdapter(WOEEngineAdapter):
16
+ def __init__(self, engine: Any, woe_suffix: str = '_woe'): ...
17
+
18
+ class MonotoneBinnerAdapter(WOEEngineAdapter):
19
+ def __init__(self, engine: Any, woe_suffix: str = '_woe'): ...
20
+
21
+ def as_woe_engine(engine: Any, woe_suffix: str = '_woe') -> Optional[WOEEngineAdapter]: ...