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.
- ExcelMaster/ExcelFormatTool.py +487 -0
- ExcelMaster/ExcelMaster.py +917 -0
- ExcelMaster/Template.py +525 -0
- ExcelMaster/Utility.py +233 -0
- ExcelMaster/__init__.py +3 -0
- Modeling_Tool/Core/Binning_Tool.py +1608 -0
- Modeling_Tool/Core/Binning_Tool.pyi +48 -0
- Modeling_Tool/Core/Check_DuckDB_Compatibility.py +835 -0
- Modeling_Tool/Core/Json_Data_Converter.py +621 -0
- Modeling_Tool/Core/Model_Registry_Tool.py +199 -0
- Modeling_Tool/Core/ODPS_Tool.py +284 -0
- Modeling_Tool/Core/Slope_Tool.py +356 -0
- Modeling_Tool/Core/Slope_Tool.pyi +31 -0
- Modeling_Tool/Core/XOR_Encryptor.py +207 -0
- Modeling_Tool/Core/XOR_Encryptor.pyi +26 -0
- Modeling_Tool/Core/__init__.py +99 -0
- Modeling_Tool/Core/kDataFrame.py +228 -0
- Modeling_Tool/Core/kDataFrame.pyi +43 -0
- Modeling_Tool/Core/sample_weight_utils.py +77 -0
- Modeling_Tool/Core/utils.py +2672 -0
- Modeling_Tool/Eval/Evaluation_Tool.py +1452 -0
- Modeling_Tool/Eval/Evaluation_Tool.pyi +47 -0
- Modeling_Tool/Eval/Model_Eval_Tool.py +2548 -0
- Modeling_Tool/Eval/Model_Eval_Tool.pyi +37 -0
- Modeling_Tool/Eval/__init__.py +54 -0
- Modeling_Tool/Eval/evaluate_model.py +2008 -0
- Modeling_Tool/Eval/evaluate_model.pyi +50 -0
- Modeling_Tool/Eval/weighted_eval_utils.py +326 -0
- Modeling_Tool/Explainability/Coalition_Structure.py +305 -0
- Modeling_Tool/Explainability/Model_Explainer.py +743 -0
- Modeling_Tool/Explainability/__init__.py +24 -0
- Modeling_Tool/Feature/Distribution_Tool.py +509 -0
- Modeling_Tool/Feature/Distribution_Tool.pyi +42 -0
- Modeling_Tool/Feature/Feature_Insights.py +762 -0
- Modeling_Tool/Feature/Feature_Insights.pyi +33 -0
- Modeling_Tool/Feature/PSI_Tool.py +1195 -0
- Modeling_Tool/Feature/PSI_Tool.pyi +29 -0
- Modeling_Tool/Feature/WOE_Engine_Feature_Patch.py +355 -0
- Modeling_Tool/Feature/__init__.py +40 -0
- Modeling_Tool/Model/Backward_Tool.py +778 -0
- Modeling_Tool/Model/Backward_Tool.pyi +45 -0
- Modeling_Tool/Model/GBM_Search_Tool.py +251 -0
- Modeling_Tool/Model/GBM_Tool.py +1610 -0
- Modeling_Tool/Model/GBM_Tool.pyi +90 -0
- Modeling_Tool/Model/LRM_Tool.py +1198 -0
- Modeling_Tool/Model/LRM_Tool.pyi +47 -0
- Modeling_Tool/Model/__init__.py +61 -0
- Modeling_Tool/Sample/Distribution_Adaptation.py +131 -0
- Modeling_Tool/Sample/Distribution_Adaptation.pyi +30 -0
- Modeling_Tool/Sample/Reject_Infer.py +413 -0
- Modeling_Tool/Sample/Reject_Infer.pyi +43 -0
- Modeling_Tool/Sample/Sample_Split.py +520 -0
- Modeling_Tool/Sample/Sample_Split.pyi +43 -0
- Modeling_Tool/Sample/__init__.py +31 -0
- Modeling_Tool/UAT/UAT_Consistency_Checker.py +1180 -0
- Modeling_Tool/UAT/__init__.py +19 -0
- Modeling_Tool/WOE/WOE_Adapter.py +204 -0
- Modeling_Tool/WOE/WOE_Adapter.pyi +21 -0
- Modeling_Tool/WOE/WOE_Master.py +491 -0
- Modeling_Tool/WOE/WOE_Master.pyi +40 -0
- Modeling_Tool/WOE/WOE_Monotone_Binner.py +3324 -0
- Modeling_Tool/WOE/WOE_Monotone_Binner.pyi +71 -0
- Modeling_Tool/WOE/WOE_Plot_Tool.py +919 -0
- Modeling_Tool/WOE/WOE_Plot_Tool.pyi +46 -0
- Modeling_Tool/WOE/WOE_Report_Builder.py +214 -0
- Modeling_Tool/WOE/WOE_Report_Builder.pyi +24 -0
- Modeling_Tool/WOE/WOE_Tool.py +1094 -0
- Modeling_Tool/WOE/WOE_Tool.pyi +41 -0
- Modeling_Tool/WOE/__init__.py +86 -0
- Modeling_Tool/WOE/plot_woe_tool.py +290 -0
- Modeling_Tool/WOE/plot_woe_tool.pyi +25 -0
- Modeling_Tool/__init__.py +176 -0
- Report/Report_Tool.py +380 -0
- Report/__init__.py +3 -0
- supermodelingfactory-0.2.0.dist-info/METADATA +268 -0
- supermodelingfactory-0.2.0.dist-info/RECORD +79 -0
- supermodelingfactory-0.2.0.dist-info/WHEEL +5 -0
- supermodelingfactory-0.2.0.dist-info/licenses/LICENSE +102 -0
- supermodelingfactory-0.2.0.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from .WOE_Plot_Tool import get_bivar_graph
|
|
6
|
+
from .WOE_Tool import mapping_woe, woe_transform
|
|
7
|
+
|
|
8
|
+
from Modeling_Tool.Core.Binning_Tool import run_binning, get_bin_range_list
|
|
9
|
+
from Modeling_Tool.Core.utils import calc_woe, calc_iv
|
|
10
|
+
|
|
11
|
+
def get_overall_woe_table(woe_master, data, varlist=None):
|
|
12
|
+
"""生成整体样本的WOE统计表,结构对齐训练集映射表。"""
|
|
13
|
+
if varlist is None:
|
|
14
|
+
varlist = woe_master.varlist
|
|
15
|
+
|
|
16
|
+
all_tables = []
|
|
17
|
+
for var in varlist:
|
|
18
|
+
var_map = woe_master.woe_dict[var]
|
|
19
|
+
|
|
20
|
+
# 提取分箱边界并保留 inf
|
|
21
|
+
edges = get_bin_range_list(var_map, col="BIN_RANGE")
|
|
22
|
+
custom_edges = sorted(set(list(edges) + [-np.inf, np.inf]))
|
|
23
|
+
|
|
24
|
+
# 从训练集 BIN_RANGE 推断闭合方式
|
|
25
|
+
first_bin = var_map["BIN_RANGE"].dropna().iloc[0]
|
|
26
|
+
include_lowest = first_bin[0] == '['
|
|
27
|
+
right = first_bin[-1] == ']'
|
|
28
|
+
|
|
29
|
+
fill_val = woe_master.missing_ref_value
|
|
30
|
+
data_proc = data.copy()
|
|
31
|
+
data_proc[var] = data_proc[var].fillna(fill_val)
|
|
32
|
+
|
|
33
|
+
# 使用训练集边界分箱
|
|
34
|
+
binned, _ = run_binning(
|
|
35
|
+
data=data_proc,
|
|
36
|
+
column=var,
|
|
37
|
+
nbins=custom_edges,
|
|
38
|
+
include_missing=True,
|
|
39
|
+
equal_freq=False,
|
|
40
|
+
bin_colnames=("_BIN_NUM", "_BIN_RANGE"),
|
|
41
|
+
ascending=True,
|
|
42
|
+
include_lowest=include_lowest,
|
|
43
|
+
right=right,
|
|
44
|
+
spec_values=[fill_val]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
dep = woe_master.dep
|
|
48
|
+
grp = binned.groupby(["_BIN_NUM", "_BIN_RANGE"], dropna=False)
|
|
49
|
+
stats = grp.agg(
|
|
50
|
+
MIN=(var, "min"),
|
|
51
|
+
MAX=(var, "max"),
|
|
52
|
+
N=(var, "count"),
|
|
53
|
+
AVG_BAD=(dep, "mean"),
|
|
54
|
+
N_BAD=(dep, "sum"),
|
|
55
|
+
N_GOOD=(dep, lambda x: (x == 0).sum())
|
|
56
|
+
).reset_index()
|
|
57
|
+
|
|
58
|
+
# 计算 WOE / IV / LIFT
|
|
59
|
+
stats["BAD_PCT_PER_BIN"] = stats["N_BAD"] / stats["N_BAD"].sum()
|
|
60
|
+
stats["GOOD_PCT_PER_BIN"] = stats["N_GOOD"] / stats["N_GOOD"].sum()
|
|
61
|
+
stats["WOE"] = calc_woe(stats, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
|
|
62
|
+
stats["IV"] = calc_iv(stats, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
|
|
63
|
+
stats["LIFT"] = stats["AVG_BAD"] / stats["AVG_BAD"].mean()
|
|
64
|
+
stats["VAR"] = var
|
|
65
|
+
|
|
66
|
+
stats = stats.rename(columns={"_BIN_NUM": "BIN_NUM", "_BIN_RANGE": "BIN_RANGE"})
|
|
67
|
+
|
|
68
|
+
cols = ["VAR", "BIN_NUM", "BIN_RANGE", "MIN", "MAX", "N",
|
|
69
|
+
"AVG_BAD", "WOE", "IV", "N_BAD", "N_GOOD",
|
|
70
|
+
"BAD_PCT_PER_BIN", "GOOD_PCT_PER_BIN", "LIFT"]
|
|
71
|
+
stats = stats[cols]
|
|
72
|
+
all_tables.append(stats)
|
|
73
|
+
|
|
74
|
+
return pd.concat(all_tables, ignore_index=True)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_group_woe_table(woe_master, data, group, varlist=None):
|
|
78
|
+
"""生成分组样本的WOE汇总、透视和详细表。"""
|
|
79
|
+
if varlist is None:
|
|
80
|
+
varlist = woe_master.varlist
|
|
81
|
+
|
|
82
|
+
summaries = []
|
|
83
|
+
pivots_woe = []
|
|
84
|
+
pivots_bad = []
|
|
85
|
+
detail_list = []
|
|
86
|
+
|
|
87
|
+
for var in varlist:
|
|
88
|
+
var_map = woe_master.woe_dict[var]
|
|
89
|
+
edges = get_bin_range_list(var_map, col="BIN_RANGE")
|
|
90
|
+
custom_edges = sorted(set(list(edges) + [-np.inf, np.inf]))
|
|
91
|
+
first_bin = var_map["BIN_RANGE"].dropna().iloc[0]
|
|
92
|
+
include_lowest = first_bin[0] == '['
|
|
93
|
+
right = first_bin[-1] == ']'
|
|
94
|
+
fill_val = woe_master.missing_ref_value
|
|
95
|
+
|
|
96
|
+
data_proc = data.copy()
|
|
97
|
+
data_proc[var] = data_proc[var].fillna(fill_val)
|
|
98
|
+
|
|
99
|
+
binned, _ = run_binning(
|
|
100
|
+
data=data_proc,
|
|
101
|
+
column=var,
|
|
102
|
+
nbins=custom_edges,
|
|
103
|
+
include_missing=True,
|
|
104
|
+
equal_freq=False,
|
|
105
|
+
bin_colnames=("_BIN_NUM", "_BIN_RANGE"),
|
|
106
|
+
ascending=True,
|
|
107
|
+
include_lowest=include_lowest,
|
|
108
|
+
right=right,
|
|
109
|
+
spec_values=[fill_val]
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
dep = woe_master.dep
|
|
113
|
+
# 按分箱与分组双重聚合
|
|
114
|
+
grp = binned.groupby([group, "_BIN_NUM", "_BIN_RANGE"], dropna=False)
|
|
115
|
+
stats = grp.agg(
|
|
116
|
+
MIN=(var, "min"),
|
|
117
|
+
MAX=(var, "max"),
|
|
118
|
+
N=(var, "count"),
|
|
119
|
+
AVG_BAD=(dep, "mean"),
|
|
120
|
+
N_BAD=(dep, "sum"),
|
|
121
|
+
N_GOOD=(dep, lambda x: (x == 0).sum())
|
|
122
|
+
).reset_index()
|
|
123
|
+
|
|
124
|
+
# 计算各分箱内 WOE(全局分母)
|
|
125
|
+
total_bad = stats["N_BAD"].sum()
|
|
126
|
+
total_good = stats["N_GOOD"].sum()
|
|
127
|
+
stats["BAD_PCT_PER_BIN"] = stats["N_BAD"] / total_bad
|
|
128
|
+
stats["GOOD_PCT_PER_BIN"] = stats["N_GOOD"] / total_good
|
|
129
|
+
stats["WOE"] = calc_woe(stats, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
|
|
130
|
+
stats["IV"] = calc_iv(stats, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
|
|
131
|
+
stats["LIFT"] = stats["AVG_BAD"] / stats["AVG_BAD"].mean()
|
|
132
|
+
stats["VAR"] = var
|
|
133
|
+
|
|
134
|
+
# 生成透视表:WOE 和 AVG_BAD 在不同分组下的值
|
|
135
|
+
pvt_woe = stats.pivot_table(index=["_BIN_NUM", "_BIN_RANGE"], columns=group, values="WOE")
|
|
136
|
+
pvt_bad = stats.pivot_table(index=["_BIN_NUM", "_BIN_RANGE"], columns=group, values="AVG_BAD")
|
|
137
|
+
|
|
138
|
+
# 汇总各分组的总指标
|
|
139
|
+
sum_grp = stats.groupby(group).agg(
|
|
140
|
+
N=("N", "sum"),
|
|
141
|
+
IV=("IV", "sum"),
|
|
142
|
+
KS_PER_BIN=("LIFT", "max"), # 简化处理,可进一步细算
|
|
143
|
+
TOP_LIFT=("LIFT", "max"),
|
|
144
|
+
BTM_LIFT=("LIFT", "min")
|
|
145
|
+
).reset_index()
|
|
146
|
+
|
|
147
|
+
# 计算单调性斜率(可选)
|
|
148
|
+
from Modeling_Tool.Core.Slope_Tool import calculate_slope_manual
|
|
149
|
+
slopes = stats.groupby(group).apply(lambda x: calculate_slope_manual(x, "AVG_BAD"))
|
|
150
|
+
sum_grp["SLOPE"] = sum_grp[group].map(slopes)
|
|
151
|
+
sum_grp["direction"] = sum_grp["SLOPE"].apply(lambda x: 1 if x > 0 else -1 if x < 0 else 0)
|
|
152
|
+
sum_grp["VAR"] = var
|
|
153
|
+
|
|
154
|
+
summaries.append(sum_grp)
|
|
155
|
+
pivots_woe.append(pvt_woe)
|
|
156
|
+
pivots_bad.append(pvt_bad)
|
|
157
|
+
detail_list.append(stats)
|
|
158
|
+
|
|
159
|
+
final_pivot = pd.concat(pivots_woe, keys=varlist, names=["VAR", "BIN_NUM", "BIN_RANGE"])
|
|
160
|
+
# 如需同时返回 AVG_BAD 透视表,可以合并或单独返回
|
|
161
|
+
return {
|
|
162
|
+
"summary": pd.concat(summaries, ignore_index=True),
|
|
163
|
+
"pivot": final_pivot,
|
|
164
|
+
"detail": pd.concat(detail_list, ignore_index=True)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class WOE_Master(object):
|
|
169
|
+
"""WOE Master class for WOE fitting, transformation, adjustment and plotting.
|
|
170
|
+
|
|
171
|
+
This class provides a complete WOE encoding workflow including:
|
|
172
|
+
- Fitting WOE bins from data
|
|
173
|
+
- Loading existing WOE mapping tables
|
|
174
|
+
- Transforming new data with WOE
|
|
175
|
+
- Updating and adjusting WOE bins
|
|
176
|
+
- Plotting bivariate WOE comparison charts
|
|
177
|
+
|
|
178
|
+
Attributes:
|
|
179
|
+
train_data: pandas.DataFrame, training dataset
|
|
180
|
+
varlist: list, variable names for WOE transformation
|
|
181
|
+
dep: str, target variable name
|
|
182
|
+
graph_save_dir: str, directory for saving graphs
|
|
183
|
+
woe_suffix: str, suffix for WOE variable names
|
|
184
|
+
missing_ref_value: int/float, reference value for missing data
|
|
185
|
+
woe_dict: dict, WOE mapping dictionary
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
def __init__(self, train_data, varlist, dep=None, graph_save_dir="", woe_suffix="_woe", missing_ref_value=-999999, remove_exist_dir = False):
|
|
189
|
+
"""Initialize WOE_Master instance.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
train_data: pandas.DataFrame, training dataset with features and target
|
|
193
|
+
varlist: list, variables to perform WOE transformation
|
|
194
|
+
dep: str, target variable name
|
|
195
|
+
graph_save_dir: str, directory to save graphs
|
|
196
|
+
woe_suffix: str, suffix for WOE variable names
|
|
197
|
+
missing_ref_value: int/float, reference value for missing values
|
|
198
|
+
"""
|
|
199
|
+
self.train_data = train_data
|
|
200
|
+
self.varlist = varlist
|
|
201
|
+
self.dep = dep
|
|
202
|
+
self.graph_save_dir = graph_save_dir
|
|
203
|
+
self.woe_suffix = woe_suffix
|
|
204
|
+
self.missing_ref_value = missing_ref_value
|
|
205
|
+
self.woe_dict = {}
|
|
206
|
+
|
|
207
|
+
if remove_exist_dir:
|
|
208
|
+
self.remove_folder(graph_save_dir)
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def remove_folder(file_path):
|
|
212
|
+
"""删除指定文件夹。
|
|
213
|
+
|
|
214
|
+
递归删除指定路径的文件夹及其所有内容,
|
|
215
|
+
如果文件夹不存在则静默处理。
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
file_path : str
|
|
220
|
+
要删除的文件夹路径
|
|
221
|
+
|
|
222
|
+
Examples
|
|
223
|
+
--------
|
|
224
|
+
>>> VarExtractionInsights.remove_folder('/path/to/folder')
|
|
225
|
+
"""
|
|
226
|
+
import shutil
|
|
227
|
+
try:
|
|
228
|
+
shutil.rmtree(file_path)
|
|
229
|
+
except Exception:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
def load_mapping_table(self, mapping_table_csv):
|
|
233
|
+
"""Load WOE mapping table from CSV file or DataFrame.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
mapping_table_csv: str or pandas.DataFrame, path to CSV or DataFrame object
|
|
237
|
+
Returns:
|
|
238
|
+
None, updates self.woe_dict and self.varlist attributes
|
|
239
|
+
Raises:
|
|
240
|
+
AttributeError: if input is neither string path nor DataFrame
|
|
241
|
+
"""
|
|
242
|
+
if isinstance(mapping_table_csv, str):
|
|
243
|
+
woe_mapping_table = pd.read_csv(mapping_table_csv)
|
|
244
|
+
elif isinstance(mapping_table_csv, pd.DataFrame):
|
|
245
|
+
woe_mapping_table = mapping_table_csv
|
|
246
|
+
else:
|
|
247
|
+
raise AttributeError("Please give either CSV path or Pandas DataFrame as an input! ")
|
|
248
|
+
|
|
249
|
+
varlist = woe_mapping_table['VAR'].unique().tolist()
|
|
250
|
+
|
|
251
|
+
woe_dict = {}
|
|
252
|
+
for var in varlist:
|
|
253
|
+
single_var_woe = woe_mapping_table.query(f"VAR == '{var}'")
|
|
254
|
+
woe_dict[var] = single_var_woe
|
|
255
|
+
|
|
256
|
+
self.woe_dict = woe_dict
|
|
257
|
+
self.varlist = varlist
|
|
258
|
+
|
|
259
|
+
def fit(self, nbins=10, equal_freq=True, tree_binning_seed=None, chi2_config=None,
|
|
260
|
+
precision=5, min_bin_prop=0.05, include_missing=True, fillna=None, spec_values=[]):
|
|
261
|
+
"""Fit WOE binning for variables in varlist.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
nbins: int, number of bins (default 10)
|
|
265
|
+
equal_freq: bool, use equal frequency binning (default True)
|
|
266
|
+
tree_binning_seed: int, random seed for tree-based binning
|
|
267
|
+
chi2_config: dict, chi-square binning configuration
|
|
268
|
+
precision: int, numerical precision (default 5)
|
|
269
|
+
min_bin_prop: float, minimum bin proportion (default 0.05)
|
|
270
|
+
include_missing: bool, include missing value bin (default True)
|
|
271
|
+
fillna: int/float, value to fill missing data
|
|
272
|
+
spec_values: list, special values to handle
|
|
273
|
+
Returns:
|
|
274
|
+
None, updates self.woe_dict attribute
|
|
275
|
+
"""
|
|
276
|
+
if fillna is None:
|
|
277
|
+
fillna = self.missing_ref_value
|
|
278
|
+
|
|
279
|
+
for var in self.varlist:
|
|
280
|
+
woe_res = woe_transform(train_df=self.train_data,
|
|
281
|
+
oot_df=None,
|
|
282
|
+
var=var,
|
|
283
|
+
dep=self.dep,
|
|
284
|
+
nbins=nbins,
|
|
285
|
+
chi2_config=chi2_config,
|
|
286
|
+
tree_binning_seed=tree_binning_seed,
|
|
287
|
+
precision=precision,
|
|
288
|
+
min_bin_prop=min_bin_prop,
|
|
289
|
+
include_missing=include_missing,
|
|
290
|
+
equal_freq=equal_freq,
|
|
291
|
+
ascending=True,
|
|
292
|
+
fillna=fillna,
|
|
293
|
+
spec_values=spec_values,
|
|
294
|
+
drop_bin_info=True,
|
|
295
|
+
ret_woe_table=True)
|
|
296
|
+
woe_table = woe_res[-1]
|
|
297
|
+
woe_table["VAR"] = var
|
|
298
|
+
woe_table = woe_table.rename(columns={f"_bin_num_{var}": "BIN_NUM", f"_bin_range_{var}": "BIN_RANGE"})
|
|
299
|
+
self.woe_dict[var] = woe_table
|
|
300
|
+
|
|
301
|
+
def get_mapping_table(self):
|
|
302
|
+
"""Get WOE mapping table for all variables.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
pandas.DataFrame with WOE mapping information for all variables
|
|
306
|
+
"""
|
|
307
|
+
return pd.concat([v for k, v in self.woe_dict.items()])
|
|
308
|
+
|
|
309
|
+
def save_mapping_table(self, save_dir):
|
|
310
|
+
"""Save WOE mapping table as CSV file.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
save_dir: str, path to save the CSV file
|
|
314
|
+
Returns:
|
|
315
|
+
None, saves file directly
|
|
316
|
+
"""
|
|
317
|
+
mapping_table = self.get_mapping_table()
|
|
318
|
+
mapping_table.to_csv(save_dir, index=False)
|
|
319
|
+
|
|
320
|
+
def transform(self, data=None, varlist=None):
|
|
321
|
+
"""Transform data using WOE encoding.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
data: pandas.DataFrame, data to transform (default: train_data)
|
|
325
|
+
varlist: list, variables to transform (default: self.varlist)
|
|
326
|
+
Returns:
|
|
327
|
+
pandas.DataFrame with WOE transformed data
|
|
328
|
+
"""
|
|
329
|
+
if data is None:
|
|
330
|
+
data = self.train_data
|
|
331
|
+
if varlist is None:
|
|
332
|
+
varlist = self.varlist
|
|
333
|
+
|
|
334
|
+
woe_mapping_table = self.get_mapping_table()
|
|
335
|
+
data_woe = mapping_woe(data, varlist, woe_mapping_table, suffix=self.woe_suffix, drop_bin_info=True)
|
|
336
|
+
return data_woe
|
|
337
|
+
|
|
338
|
+
def update_woe(self, varlist, nbins=10, equal_freq=True, tree_binning_seed=None, chi2_config=None,
|
|
339
|
+
precision=5, min_bin_prop=0.05, include_missing=True, fillna=None, spec_values=[]):
|
|
340
|
+
"""Update WOE binning for specified variables.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
varlist: list, variables to update WOE for
|
|
344
|
+
nbins: int, number of bins (default 10)
|
|
345
|
+
equal_freq: bool, use equal frequency binning (default True)
|
|
346
|
+
tree_binning_seed: int, random seed for tree-based binning
|
|
347
|
+
chi2_config: dict, chi-square binning configuration
|
|
348
|
+
precision: int, numerical precision (default 5)
|
|
349
|
+
min_bin_prop: float, minimum bin proportion (default 0.05)
|
|
350
|
+
include_missing: bool, include missing value bin (default True)
|
|
351
|
+
fillna: int/float, value to fill missing data
|
|
352
|
+
spec_values: list, special values to handle
|
|
353
|
+
Returns:
|
|
354
|
+
None, updates self.woe_dict attribute
|
|
355
|
+
"""
|
|
356
|
+
if fillna is None:
|
|
357
|
+
fillna = self.missing_ref_value
|
|
358
|
+
|
|
359
|
+
new_woe_dict = {}
|
|
360
|
+
for var in varlist:
|
|
361
|
+
woe_res = woe_transform(train_df=self.train_data,
|
|
362
|
+
oot_df=None,
|
|
363
|
+
var=var,
|
|
364
|
+
dep=self.dep,
|
|
365
|
+
nbins=nbins,
|
|
366
|
+
chi2_config=chi2_config,
|
|
367
|
+
tree_binning_seed=tree_binning_seed,
|
|
368
|
+
precision=precision,
|
|
369
|
+
min_bin_prop=min_bin_prop,
|
|
370
|
+
include_missing=include_missing,
|
|
371
|
+
equal_freq=equal_freq,
|
|
372
|
+
ascending=True,
|
|
373
|
+
fillna=fillna,
|
|
374
|
+
spec_values=spec_values,
|
|
375
|
+
drop_bin_info=True,
|
|
376
|
+
ret_woe_table=True)
|
|
377
|
+
woe_table = woe_res[-1]
|
|
378
|
+
woe_table["VAR"] = var
|
|
379
|
+
woe_table = woe_table.rename(columns={f"_bin_num_{var}": "BIN_NUM", f"_bin_range_{var}": "BIN_RANGE"})
|
|
380
|
+
new_woe_dict[var] = woe_table
|
|
381
|
+
|
|
382
|
+
self.woe_dict.update(new_woe_dict)
|
|
383
|
+
|
|
384
|
+
def plot_bivar_graph(self, data, group, dirname, varlist=None):
|
|
385
|
+
"""Plot bivariate WOE comparison graph.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
data: pandas.DataFrame, data for plotting
|
|
389
|
+
group: str, grouping variable name for distinguishing curves
|
|
390
|
+
dirname: str, subdirectory name for saving (under graph_save_dir)
|
|
391
|
+
varlist: list, variables to plot (default: self.varlist)
|
|
392
|
+
Returns:
|
|
393
|
+
None, saves images directly
|
|
394
|
+
"""
|
|
395
|
+
if varlist is None:
|
|
396
|
+
varlist = self.varlist
|
|
397
|
+
|
|
398
|
+
get_bivar_graph(data=data,
|
|
399
|
+
varlist=varlist,
|
|
400
|
+
sep=self.dep,
|
|
401
|
+
ref_woe_table=self.get_mapping_table(),
|
|
402
|
+
group=group,
|
|
403
|
+
save_dir=os.path.join(self.graph_save_dir, dirname))
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
# =============================================================================
|
|
407
|
+
# Standalone Function Wrappers
|
|
408
|
+
# =============================================================================
|
|
409
|
+
|
|
410
|
+
def load_mapping_table(mapping_table_csv):
|
|
411
|
+
"""Load WOE mapping table from CSV or DataFrame.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
mapping_table_csv: str or pandas.DataFrame, path to CSV or DataFrame
|
|
415
|
+
Returns:
|
|
416
|
+
tuple: (varlist, woe_dict)
|
|
417
|
+
Raises:
|
|
418
|
+
AttributeError: if input is neither string path nor DataFrame
|
|
419
|
+
"""
|
|
420
|
+
if isinstance(mapping_table_csv, str):
|
|
421
|
+
woe_mapping_table = pd.read_csv(mapping_table_csv)
|
|
422
|
+
elif isinstance(mapping_table_csv, pd.DataFrame):
|
|
423
|
+
woe_mapping_table = mapping_table_csv
|
|
424
|
+
else:
|
|
425
|
+
raise AttributeError("Please give either CSV path or Pandas DataFrame as an input! ")
|
|
426
|
+
|
|
427
|
+
varlist = woe_mapping_table['VAR'].unique().tolist()
|
|
428
|
+
woe_dict = {}
|
|
429
|
+
for var in varlist:
|
|
430
|
+
single_var_woe = woe_mapping_table.query(f"VAR == '{var}'")
|
|
431
|
+
woe_dict[var] = single_var_woe
|
|
432
|
+
return varlist, woe_dict
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def get_mapping_table(woe_dict):
|
|
436
|
+
"""Get combined mapping table from WOE dictionary.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
woe_dict: dict, WOE mapping dictionary
|
|
440
|
+
Returns:
|
|
441
|
+
pandas.DataFrame with WOE mapping information
|
|
442
|
+
"""
|
|
443
|
+
return pd.concat([v for k, v in woe_dict.items()])
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def save_mapping_table(woe_dict, save_dir):
|
|
447
|
+
"""Save WOE dictionary as CSV file.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
woe_dict: dict, WOE mapping dictionary
|
|
451
|
+
save_dir: str, path to save the CSV file
|
|
452
|
+
Returns:
|
|
453
|
+
None, saves file directly
|
|
454
|
+
"""
|
|
455
|
+
mapping_table = get_mapping_table(woe_dict)
|
|
456
|
+
mapping_table.to_csv(save_dir, index=False)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def transform(data, varlist, woe_mapping_table, woe_suffix="_woe"):
|
|
460
|
+
"""Transform data using WOE encoding.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
data: pandas.DataFrame, data to transform
|
|
464
|
+
varlist: list, variables to transform
|
|
465
|
+
woe_mapping_table: pandas.DataFrame, WOE mapping table
|
|
466
|
+
woe_suffix: str, suffix for WOE variable names (default "_woe")
|
|
467
|
+
Returns:
|
|
468
|
+
pandas.DataFrame with WOE transformed data
|
|
469
|
+
"""
|
|
470
|
+
return mapping_woe(data, varlist, woe_mapping_table, suffix=woe_suffix, drop_bin_info=True)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def plot_bivar_graph_func(data, varlist, dep, ref_woe_table, group, save_dir):
|
|
474
|
+
"""Plot bivariate WOE comparison graph.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
data: pandas.DataFrame, data for plotting
|
|
478
|
+
varlist: list, variables to plot
|
|
479
|
+
dep: str, target variable name
|
|
480
|
+
ref_woe_table: pandas.DataFrame, reference WOE mapping table
|
|
481
|
+
group: str, grouping variable name for distinguishing curves
|
|
482
|
+
save_dir: str, directory path to save images
|
|
483
|
+
Returns:
|
|
484
|
+
None, saves images directly
|
|
485
|
+
"""
|
|
486
|
+
get_bivar_graph(data=data,
|
|
487
|
+
varlist=varlist,
|
|
488
|
+
sep=dep,
|
|
489
|
+
ref_woe_table=ref_woe_table,
|
|
490
|
+
group=group,
|
|
491
|
+
save_dir=save_dir)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Modeling_Tool.WOE.WOE_Master
|
|
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-WOEMASTER-984661fa
|
|
12
|
+
# (Unique trace marker. Do not remove or alter — used for plagiarism
|
|
13
|
+
# detection across the public internet.)
|
|
14
|
+
# =============================================================================
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import pandas as pd
|
|
18
|
+
import numpy as np
|
|
19
|
+
from .WOE_Plot_Tool import get_bivar_graph
|
|
20
|
+
from .WOE_Tool import mapping_woe, woe_transform
|
|
21
|
+
from Modeling_Tool.Core.Binning_Tool import run_binning, get_bin_range_list
|
|
22
|
+
from Modeling_Tool.Core.utils import calc_woe, calc_iv
|
|
23
|
+
def get_overall_woe_table(woe_master, data, varlist = None): ...
|
|
24
|
+
def get_group_woe_table(woe_master, data, group, varlist = None): ...
|
|
25
|
+
|
|
26
|
+
class WOE_Master(object):
|
|
27
|
+
def __init__(self, train_data, varlist, dep = None, graph_save_dir = '', woe_suffix = '_woe', missing_ref_value = -999999, remove_exist_dir = False): ...
|
|
28
|
+
def remove_folder(file_path): ...
|
|
29
|
+
def load_mapping_table(self, mapping_table_csv): ...
|
|
30
|
+
def fit(self, nbins = 10, equal_freq = True, tree_binning_seed = None, chi2_config = None, precision = 5, min_bin_prop = 0.05, include_missing = True, fillna = None, spec_values = []): ...
|
|
31
|
+
def get_mapping_table(self): ...
|
|
32
|
+
def save_mapping_table(self, save_dir): ...
|
|
33
|
+
def transform(self, data = None, varlist = None): ...
|
|
34
|
+
def update_woe(self, varlist, nbins = 10, equal_freq = True, tree_binning_seed = None, chi2_config = None, precision = 5, min_bin_prop = 0.05, include_missing = True, fillna = None, spec_values = []): ...
|
|
35
|
+
def plot_bivar_graph(self, data, group, dirname, varlist = None): ...
|
|
36
|
+
def load_mapping_table(mapping_table_csv): ...
|
|
37
|
+
def get_mapping_table(woe_dict): ...
|
|
38
|
+
def save_mapping_table(woe_dict, save_dir): ...
|
|
39
|
+
def transform(data, varlist, woe_mapping_table, woe_suffix = '_woe'): ...
|
|
40
|
+
def plot_bivar_graph_func(data, varlist, dep, ref_woe_table, group, save_dir): ...
|