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,1094 @@
1
+ """
2
+ WOE转换与单调性分析工具包
3
+ 提供WOE分箱、转换、映射及单调性检验功能
4
+ """
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ import logging
9
+
10
+ from Modeling_Tool.Core.Binning_Tool import run_binning, super_binning, get_bin_range_list
11
+ from Modeling_Tool.Core.Slope_Tool import calculate_slope_manual
12
+ from Modeling_Tool.Core.utils import calc_iv, calc_woe
13
+
14
+ def is_monotonic(data, column, direction='auto', strict=False, handle_nan='drop'):
15
+ """检查Pandas Series或DataFrame列是否单调(递增或递减)。
16
+
17
+ 参数:
18
+ -----------
19
+ data : pd.DataFrame
20
+ 包含数据的数据框
21
+ column : str
22
+ 要检查的列名
23
+ direction : str, optional
24
+ 检查方向,'auto'(自动检测)、'increasing'(递增)或'decreasing'(递减),
25
+ 默认为'auto'
26
+ strict : bool, optional
27
+ 是否要求严格单调(不允许相等值),默认为False
28
+ handle_nan : str, optional
29
+ 处理NaN值的方法,可选'drop'(忽略)、'forward'(向前填充)、
30
+ 'backward'(向后填充)或'error'(报错),默认为'drop'
31
+
32
+ 返回:
33
+ --------
34
+ tuple
35
+ (是否单调, 单调方向) 的元组。
36
+ 是否单调为bool值,方向为1(递增)、-1(递减)或0(非单调)
37
+ """
38
+ series = data[column]
39
+
40
+ # 处理NaN值
41
+ if series.isna().any():
42
+ if handle_nan == 'drop':
43
+ series = series.dropna()
44
+ elif handle_nan == 'forward':
45
+ series = series.ffill()
46
+ elif handle_nan == 'backward':
47
+ series = series.bfill()
48
+ elif handle_nan == 'error':
49
+ raise ValueError("序列包含NaN值")
50
+ else:
51
+ raise ValueError("handle_nan参数必须是'drop'、'forward'、'backward'或'error'")
52
+
53
+ # 如果序列为空或只有一个元素,则认为是单调的
54
+ if len(series) <= 1:
55
+ return True, 0 if len(series) == 0 else 0
56
+
57
+ # 计算差值
58
+ diffs = series.diff().iloc[1:]
59
+
60
+ # 检查单调性
61
+ if direction == 'auto':
62
+ if strict:
63
+ if (diffs > 0).all(): # 所有差值都为正
64
+ return True, 1
65
+ elif (diffs < 0).all(): # 所有差值都为负
66
+ return True, -1
67
+ else:
68
+ return False, 0
69
+ else:
70
+ if (diffs >= 0).all(): # 所有差值都非负
71
+ return True, 1
72
+ elif (diffs <= 0).all(): # 所有差值都非正
73
+ return True, -1
74
+ else:
75
+ return False, 0
76
+ elif direction == 'increasing':
77
+ if strict:
78
+ is_mono = (diffs > 0).all()
79
+ else:
80
+ is_mono = (diffs >= 0).all()
81
+ return is_mono, 1 if is_mono else 0
82
+ elif direction == 'decreasing':
83
+ if strict:
84
+ is_mono = (diffs < 0).all()
85
+ else:
86
+ is_mono = (diffs <= 0).all()
87
+ return is_mono, -1 if is_mono else 0
88
+ else:
89
+ raise ValueError("direction参数必须是'auto'、'increasing'或'decreasing'")
90
+
91
+
92
+ def check_monotonicity(data, var):
93
+ """检查WOE值的单调性。
94
+
95
+ 对指定变量验证其WOE值是否满足单调性要求,
96
+ 用于评估分箱效果是否符合业务逻辑。
97
+
98
+ 参数:
99
+ -----------
100
+ data : pd.DataFrame
101
+ 包含分箱信息和WOE值的数据框
102
+ var : str
103
+ 待检查的变量名
104
+
105
+ 返回:
106
+ --------
107
+ tuple
108
+ (是否单调, 单调方向) 的元组,格式同 is_monotonic 函数
109
+
110
+ 示例:
111
+ --------
112
+ >>> result = check_monotonicity(woe_df, 'age')
113
+ """
114
+ df_grp = data.groupby([f"_bin_num_{var}"]).agg(
115
+ {f"_bin_num_{var}": "count", var: [min, max], f"{var}_woe": [min, max, "mean"]}
116
+ )
117
+ assert (df_grp[(f"{var}_woe", "min")] == df_grp[(f"{var}_woe", "max")]).all()
118
+ woe = pd.DataFrame(df_grp.loc[df_grp[(var, "min")] != df_grp[(var, "max")], (f"{var}_woe", "min")])
119
+ res = is_monotonic(woe, (f"{var}_woe", "min"))
120
+ return res
121
+
122
+
123
+ class WOETransformer:
124
+ """WOE转换器。
125
+
126
+ 提供WOE分箱、转换和单调性检验的完整功能,
127
+ 支持单变量和多变量批量处理,支持训练集和验证集的WOE映射。
128
+
129
+ 参数:
130
+ -----------
131
+ nbins : int, optional
132
+ 分箱数量,默认为10
133
+ precision : int, optional
134
+ WOE和IV计算精度,默认为5
135
+ min_bin_prop : float, optional
136
+ 每个分箱的最小样本比例,默认为0.05
137
+ include_missing : bool, optional
138
+ 是否将缺失值作为单独分箱,默认为False
139
+ equal_freq : bool, optional
140
+ 是否使用等频分箱,默认为True
141
+ fillna : int/float, optional
142
+ 缺失值填充值,默认为-999999
143
+ chi2_config : tuple, optional
144
+ 卡方分箱配置,(init_bins, p_value)元组,默认为None
145
+ tree_binning_seed : int, optional
146
+ 决策树分箱随机种子,默认为None
147
+ spec_values : list, optional
148
+ 特殊值列表,默认为空列表
149
+ drop_bin_info : bool, optional
150
+ 是否删除中间分箱信息列,默认为True
151
+ ret_woe_table : bool, optional
152
+ 是否返回WOE映射表,默认为True
153
+
154
+ 示例:
155
+ --------
156
+ >>> transformer = WOETransformer(nbins=10)
157
+ >>> result = transformer.transform(df, ['var1', 'var2'], 'target')
158
+ """
159
+
160
+ def __init__(self, nbins=10, precision=5, min_bin_prop=0.05, include_missing=False,
161
+ equal_freq=True, fillna=-999999, chi2_config=None, tree_binning_seed=None,
162
+ spec_values=None, drop_bin_info=True, ret_woe_table=True):
163
+ """初始化WOE转换器。
164
+
165
+ 参数:
166
+ -----------
167
+ nbins : int, optional
168
+ 分箱数量
169
+ precision : int, optional
170
+ WOE和IV计算精度
171
+ min_bin_prop : float, optional
172
+ 每个分箱的最小样本比例
173
+ include_missing : bool, optional
174
+ 是否将缺失值作为单独分箱
175
+ equal_freq : bool, optional
176
+ 是否使用等频分箱
177
+ fillna : int/float, optional
178
+ 缺失值填充值
179
+ chi2_config : tuple, optional
180
+ 卡方分箱配置
181
+ tree_binning_seed : int, optional
182
+ 决策树分箱随机种子
183
+ spec_values : list, optional
184
+ 特殊值列表
185
+ drop_bin_info : bool, optional
186
+ 是否删除中间分箱信息列
187
+ ret_woe_table : bool, optional
188
+ 是否返回WOE映射表
189
+ """
190
+ self.nbins = nbins
191
+ self.precision = precision
192
+ self.min_bin_prop = min_bin_prop
193
+ self.include_missing = include_missing
194
+ self.equal_freq = equal_freq
195
+ self.fillna = fillna
196
+ self.chi2_config = chi2_config
197
+ self.tree_binning_seed = tree_binning_seed
198
+ self.spec_values = spec_values if spec_values is not None else []
199
+ self.drop_bin_info = drop_bin_info
200
+ self.ret_woe_table = ret_woe_table
201
+
202
+ def _get_woe_table(self, binning_res, var, dep):
203
+ """根据分箱结果计算WOE表。
204
+
205
+ 参数:
206
+ -----------
207
+ binning_res : pd.DataFrame
208
+ 分箱结果数据框
209
+ var : str
210
+ 变量名
211
+ dep : str
212
+ 目标变量名
213
+
214
+ 返回:
215
+ --------
216
+ tuple
217
+ (woe_table, woe_mapping_dict) 元组
218
+ """
219
+ woe_table = binning_res.groupby([f"_bin_num_{var}", f"_bin_range_{var}"], dropna=False)\
220
+ .agg(
221
+ MIN=(var, "min"),
222
+ MAX=(var, "max"),
223
+ N=(f"_bin_num_{var}", "count"),
224
+ AVG_SCORE=(var, "mean"),
225
+ AVG_BAD=(dep, lambda x: ((x == 1).sum() / x.count())),
226
+ AVG_GOOD=(dep, lambda x: ((x == 0).sum() / x.count())),
227
+ N_BAD=(dep, "sum"),
228
+ N_GOOD=(dep, lambda x: (x == 0).sum())
229
+ )
230
+
231
+ # IV/WOE Calculation
232
+ woe_table["BAD_PCT_PER_BIN"] = woe_table["N_BAD"] / woe_table["N_BAD"].sum()
233
+ woe_table["GOOD_PCT_PER_BIN"] = woe_table["N_GOOD"] / woe_table["N_GOOD"].sum()
234
+ woe_table["LIFT"] = woe_table['AVG_BAD'] / woe_table['AVG_BAD'].mean()
235
+ woe_table["WOE"] = calc_woe(data=woe_table, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
236
+ woe_table["IV"] = calc_iv(data=woe_table, bad_pct="BAD_PCT_PER_BIN", good_pct="GOOD_PCT_PER_BIN")
237
+
238
+ # WOE Mapping Dictionary
239
+ woe_table = woe_table.reset_index(drop=False)
240
+ woe_mapping_dict = dict(zip(woe_table[f"_bin_range_{var}"], woe_table["WOE"]))
241
+
242
+ return woe_table, woe_mapping_dict
243
+
244
+ def transform_single(self, train_df, var, dep, oot_df=None, check_monotonicity_flag=False):
245
+ """对单个变量进行WOE转换。
246
+
247
+ 参数:
248
+ -----------
249
+ train_df : pd.DataFrame
250
+ 训练数据集
251
+ var : str
252
+ 待转换的变量名
253
+ dep : str
254
+ 目标变量(因变量)名
255
+ oot_df : pd.DataFrame, optional
256
+ 验证/测试数据集,默认为None
257
+ check_monotonicity_flag : bool, optional
258
+ 是否检查单调性,默认为False
259
+
260
+ 返回:
261
+ --------
262
+ tuple/list
263
+ 根据参数返回训练结果、验证结果和WOE映射表
264
+ """
265
+ chi2_method = False
266
+ if self.chi2_config:
267
+ chi2_method = True
268
+ else:
269
+ self.chi2_config = (100, 0.99)
270
+
271
+ tree_binning = False
272
+ if self.tree_binning_seed:
273
+ tree_binning = True
274
+
275
+ train_res, train_edges = super_binning(
276
+ data=train_df,
277
+ score=var,
278
+ dep=dep,
279
+ nbins=self.nbins,
280
+ precision=self.precision,
281
+ min_bin_prop=self.min_bin_prop,
282
+ include_missing=self.include_missing,
283
+ equal_freq=self.equal_freq,
284
+ chi2_method=chi2_method,
285
+ chi2_p=self.chi2_config[1],
286
+ init_equi_bins=self.chi2_config[0],
287
+ fillna=self.fillna,
288
+ spec_values=self.spec_values,
289
+ tree_binning=tree_binning,
290
+ random_state=self.tree_binning_seed,
291
+ return_edges=True,
292
+ bin_colnames=(f"_bin_num_{var}", f"_bin_range_{var}"),
293
+ ascending=True
294
+ )
295
+
296
+ train_woe_table, train_woe_mapping_dict = self._get_woe_table(train_res, var, dep)
297
+
298
+ if check_monotonicity_flag:
299
+ if not is_monotonic(train_woe_table.query("MIN != MAX"), "WOE")[0]:
300
+ logging.warning(f"WARNING: {var} WOE values are NOT monotonic in Train Dataset!")
301
+
302
+ # WOE Mapping to DataFrame
303
+ train_res[f"{var}_woe"] = train_res[f"_bin_range_{var}"].map(train_woe_mapping_dict)
304
+
305
+ # Drop Bin Info
306
+ if self.drop_bin_info:
307
+ train_res = train_res.drop(columns=[f"_bin_num_{var}", f"_bin_range_{var}"])
308
+
309
+ if oot_df is not None:
310
+ woe_mapping_table = train_woe_table.copy()
311
+ woe_mapping_table["BIN_RANGE"] = woe_mapping_table[f"_bin_range_{var}"]
312
+ woe_mapping_table["BIN_NUM"] = woe_mapping_table[f"_bin_num_{var}"]
313
+ woe_mapping_table["VAR"] = var
314
+ oot_res = _mapping_woe_single_var(
315
+ data=oot_df, var=var, woe_mapping_table=woe_mapping_table
316
+ )
317
+
318
+ if self.ret_woe_table and oot_df is not None:
319
+ return train_res, oot_res, train_woe_table
320
+
321
+ if self.ret_woe_table and oot_df is None:
322
+ return train_res, train_woe_table
323
+
324
+ if oot_df is not None:
325
+ return train_res, oot_res
326
+
327
+ return train_res
328
+
329
+ def transform(self, train_df, varlist, dep, oot_df=None, check_monotonicity_flag=False):
330
+ """对多个变量进行WOE转换。
331
+
332
+ 参数:
333
+ -----------
334
+ train_df : pd.DataFrame
335
+ 训练数据集
336
+ varlist : list
337
+ 待转换的变量名列表
338
+ dep : str
339
+ 目标变量(因变量)名
340
+ oot_df : pd.DataFrame, optional
341
+ 验证/测试数据集,默认为None
342
+ check_monotonicity_flag : bool, optional
343
+ 是否检查单调性,默认为False
344
+
345
+ 返回:
346
+ --------
347
+ tuple/list
348
+ 返回结果的字典和WOE映射表。
349
+ 字典键为'TRAIN'和'OOT'(当oot_df不为None时)
350
+
351
+ 示例:
352
+ --------
353
+ >>> transformer = WOETransformer(nbins=10)
354
+ >>> result = transformer.transform(df, ['var1', 'var2'], 'target')
355
+ """
356
+ fnl_res = {}
357
+ for i, var in enumerate(varlist):
358
+ woe_res = self.transform_single(
359
+ train_df=train_df,
360
+ var=var,
361
+ dep=dep,
362
+ oot_df=oot_df,
363
+ check_monotonicity_flag=check_monotonicity_flag
364
+ )
365
+
366
+ train_df = woe_res[0]
367
+ if oot_df is not None:
368
+ oot_df = woe_res[1]
369
+
370
+ if i == 0:
371
+ train_woe_table = woe_res[-1]
372
+ train_woe_table["VAR"] = var
373
+ train_woe_table = train_woe_table.rename(columns={
374
+ f"_bin_num_{var}": "BIN_NUM",
375
+ f"_bin_range_{var}": "BIN_RANGE"
376
+ })
377
+ else:
378
+ train_woe_table_append = woe_res[-1]
379
+ train_woe_table_append["VAR"] = var
380
+ train_woe_table_append = train_woe_table_append.rename(columns={
381
+ f"_bin_num_{var}": "BIN_NUM",
382
+ f"_bin_range_{var}": "BIN_RANGE"
383
+ })
384
+
385
+ if i > 0:
386
+ train_woe_table = pd.concat([train_woe_table, train_woe_table_append])
387
+
388
+ fnl_res["TRAIN"] = train_df
389
+ if oot_df is not None:
390
+ fnl_res["OOT"] = oot_df
391
+
392
+ if self.ret_woe_table:
393
+ return fnl_res, train_woe_table
394
+
395
+ return fnl_res
396
+
397
+
398
+ def convert_single_var_woe(data, var, woe_mapping_table, missing_ref=None, ret_bin_no=False):
399
+ """将原始变量值转换为WOE值。
400
+
401
+ 根据预计算的WOE映射表,对指定变量进行WOE转换。
402
+ 支持缺失值处理和分箱编号返回。
403
+
404
+ 参数:
405
+ -----------
406
+ data : pd.DataFrame
407
+ 输入的数据框
408
+ var : str
409
+ 待转换的变量名
410
+ woe_mapping_table : pd.DataFrame
411
+ WOE映射表,包含bin_no、bin_value、woe和n列
412
+ missing_ref : any, optional
413
+ 缺失值参考值,默认为None
414
+ ret_bin_no : bool, optional
415
+ 是否返回分箱编号而非WOE值,默认为False
416
+
417
+ 返回:
418
+ --------
419
+ pd.Series/pd.Categorical
420
+ 转换后的WOE值或分箱编号
421
+
422
+ 示例:
423
+ --------
424
+ >>> woe_values = convert_single_var_woe(df, 'age', woe_table)
425
+ """
426
+ var_woe_mapping = woe_mapping_table.query(f"var_name == '{var}_woe'")
427
+ var_woe_mapping = var_woe_mapping[["bin_no", "bin_value", "woe", "n"]]
428
+
429
+ var_woe_mapping["bin_value_list"] = var_woe_mapping["bin_value"].apply(
430
+ lambda x: x.replace("[", "").replace(")", "").split(",")
431
+ )
432
+
433
+ woe_mapping_dict = dict(zip(var_woe_mapping['bin_no'], var_woe_mapping['woe']))
434
+ bin_range = [
435
+ float(v.strip()) if v.strip() != 'inf' else np.inf
436
+ for x in var_woe_mapping["bin_value_list"].tolist()
437
+ for v in x
438
+ ]
439
+
440
+ unique_range = []
441
+ for x in bin_range:
442
+ if x not in unique_range:
443
+ unique_range.append(x)
444
+
445
+ if missing_ref:
446
+ var_serires = data[var].fillna(missing_ref)
447
+
448
+ bin_no_transform = pd.cut(
449
+ var_serires,
450
+ bins=unique_range,
451
+ right=False,
452
+ labels=[x for x in range(0, len(unique_range) - 1)]
453
+ )
454
+
455
+ if ret_bin_no:
456
+ return bin_no_transform
457
+
458
+ woe_res = bin_no_transform.map(woe_mapping_dict)
459
+
460
+ return woe_res
461
+
462
+
463
+ class WOEMappingTransformer:
464
+ """基于WOE映射表的转换器。
465
+
466
+ 使用预计算的WOE映射表对新数据进行WOE转换,
467
+ 支持单变量和多变量批量处理。
468
+
469
+ 参数:
470
+ -----------
471
+ woe_mapping_table : pd.DataFrame
472
+ WOE映射表
473
+ missing_ref : any, optional
474
+ 缺失值参考值,默认为None
475
+ ret_bin_no : bool, optional
476
+ 是否返回分箱编号,默认为False
477
+ ret_category : bool, optional
478
+ 是否返回分类类型,默认为False
479
+ rename_orig_var : bool, optional
480
+ 是否重命名原始变量,默认为False
481
+ suffix : str, optional
482
+ 变量名后缀,默认为''
483
+
484
+ 示例:
485
+ --------
486
+ >>> transformer = WOEMappingTransformer(woe_mapping_table)
487
+ >>> result = transformer.transform(df, ['var1', 'var2'])
488
+ """
489
+
490
+ def __init__(self, woe_mapping_table, missing_ref=None, ret_bin_no=False,
491
+ ret_category=False, rename_orig_var=False, suffix=''):
492
+ """初始化WOE映射转换器。
493
+
494
+ 参数:
495
+ -----------
496
+ woe_mapping_table : pd.DataFrame
497
+ WOE映射表
498
+ missing_ref : any, optional
499
+ 缺失值参考值
500
+ ret_bin_no : bool, optional
501
+ 是否返回分箱编号
502
+ ret_category : bool, optional
503
+ 是否返回分类类型
504
+ rename_orig_var : bool, optional
505
+ 是否重命名原始变量
506
+ suffix : str, optional
507
+ 变量名后缀
508
+ """
509
+ self.woe_mapping_table = woe_mapping_table
510
+ self.missing_ref = missing_ref
511
+ self.ret_bin_no = ret_bin_no
512
+ self.ret_category = ret_category
513
+ self.rename_orig_var = rename_orig_var
514
+ self.suffix = suffix
515
+
516
+ def transform_single(self, data, var):
517
+ """对单个变量进行WOE转换。
518
+
519
+ 参数:
520
+ -----------
521
+ data : pd.DataFrame
522
+ 输入的数据框
523
+ var : str
524
+ 待转换的变量名
525
+
526
+ 返回:
527
+ --------
528
+ pd.DataFrame
529
+ 转换后的数据框
530
+ """
531
+ if self.rename_orig_var:
532
+ data = data.rename(columns={var: (var + self.suffix)})
533
+ data[var] = data[(var + self.suffix)].copy()
534
+ data[var] = convert_single_var_woe(
535
+ data, var, self.woe_mapping_table,
536
+ self.missing_ref, self.ret_bin_no
537
+ )
538
+ if not self.ret_category:
539
+ data[var] = data[var].astype(float)
540
+ else:
541
+ data[var + self.suffix] = convert_single_var_woe(
542
+ data, var, self.woe_mapping_table,
543
+ self.missing_ref, self.ret_bin_no
544
+ )
545
+ if not self.ret_category:
546
+ data[var + self.suffix] = data[var + self.suffix].astype(float)
547
+
548
+ return data
549
+
550
+ def transform(self, data, varlist):
551
+ """对多个变量进行WOE转换。
552
+
553
+ 参数:
554
+ -----------
555
+ data : pd.DataFrame
556
+ 输入的数据框
557
+ varlist : list
558
+ 待转换的变量名列表
559
+
560
+ 返回:
561
+ --------
562
+ pd.DataFrame
563
+ 转换后的数据框
564
+
565
+ 示例:
566
+ --------
567
+ >>> transformer = WOEMappingTransformer(woe_mapping_table)
568
+ >>> result = transformer.transform(df, ['var1', 'var2'])
569
+ """
570
+ res = data.copy()
571
+ for var in varlist:
572
+ res = self.transform_single(res, var)
573
+ return res
574
+
575
+
576
+ def woe_transform_cdaml(data, varlist, woe_mapping_path, missing_ref=None,
577
+ ret_bin_no=False, ret_category=False, rename_orig_var=False, suffix=''):
578
+ """使用cdaml包进行WOE转换。
579
+
580
+ 从文件路径读取WOE映射表或直接使用映射表数据框,
581
+ 对指定变量列表进行WOE转换。
582
+
583
+ 参数:
584
+ -----------
585
+ data : pd.DataFrame
586
+ 输入的数据框
587
+ varlist : list
588
+ 待转换的变量名列表
589
+ woe_mapping_path : str/pd.DataFrame
590
+ WOE映射表文件路径或数据框
591
+ missing_ref : any, optional
592
+ 缺失值参考值,默认为None
593
+ ret_bin_no : bool, optional
594
+ 是否返回分箱编号,默认为False
595
+ ret_category : bool, optional
596
+ 是否返回分类类型,默认为False
597
+ rename_orig_var : bool, optional
598
+ 是否重命名原始变量,默认为False
599
+ suffix : str, optional
600
+ 变量名后缀,默认为''
601
+
602
+ 返回:
603
+ --------
604
+ pd.DataFrame
605
+ 转换后的数据框
606
+
607
+ 示例:
608
+ --------
609
+ >>> result = woe_transform_cdaml(df, ['var1', 'var2'], 'woe_mapping.csv')
610
+ """
611
+ woe_mapping_table = pd.read_csv(woe_mapping_path) if isinstance(woe_mapping_path, str) else woe_mapping_path
612
+ woe_mapping_table.columns = [x.lower() for x in woe_mapping_table.columns]
613
+
614
+ transformer = WOEMappingTransformer(
615
+ woe_mapping_table=woe_mapping_table,
616
+ missing_ref=missing_ref,
617
+ ret_bin_no=ret_bin_no,
618
+ ret_category=ret_category,
619
+ rename_orig_var=rename_orig_var,
620
+ suffix=suffix
621
+ )
622
+ return transformer.transform(data, varlist)
623
+
624
+
625
+ def get_woe_table(data, var, dep, grp_name=None, nbins=10, precision=5,
626
+ min_bin_prop=0.05, include_missing=True, equal_freq=True,
627
+ fillna=-999999, chi2_config=None, tree_binning_seed=None, spec_values=None):
628
+ """获取WOE分箱表。
629
+
630
+ 对指定变量进行分箱处理,计算各分箱的WOE值、IV值等统计量。
631
+ 支持分组分析和单调性检验。
632
+
633
+ 参数:
634
+ -----------
635
+ data : pd.DataFrame
636
+ 输入的数据框
637
+ var : str
638
+ 待分析的变量名
639
+ dep : str
640
+ 目标变量(因变量)名
641
+ grp_name : str, optional
642
+ 分组变量名,默认为None
643
+ nbins : int, optional
644
+ 分箱数量,默认为10
645
+ precision : int, optional
646
+ 计算精度,默认为5
647
+ min_bin_prop : float, optional
648
+ 每个分箱的最小样本比例,默认为0.05
649
+ include_missing : bool, optional
650
+ 是否将缺失值作为单独分箱,默认为True
651
+ equal_freq : bool, optional
652
+ 是否使用等频分箱,默认为True
653
+ fillna : int/float, optional
654
+ 缺失值填充值,默认为-999999
655
+ chi2_config : tuple, optional
656
+ 卡方分箱配置,(init_bins, p_value)元组,默认为None
657
+ tree_binning_seed : int, optional
658
+ 决策树分箱随机种子,默认为None
659
+ spec_values : list, optional
660
+ 特殊值列表,默认为None
661
+
662
+ 返回:
663
+ --------
664
+ tuple/pd.DataFrame
665
+ 当grp_name不为None时返回(woe_table, grp_summary, grp_woe_pvt)元组;
666
+ 当grp_name为None时返回(woe_table, is_monotonic, direction, slope)元组
667
+
668
+ 示例:
669
+ --------
670
+ >>> woe_table, is_mono, direction, slope = get_woe_table(df, 'age', 'target')
671
+ """
672
+ from pandas.api.types import is_numeric_dtype, is_string_dtype
673
+
674
+ if spec_values is None:
675
+ spec_values = []
676
+
677
+ chi2_method = False
678
+ if chi2_config:
679
+ chi2_method = True
680
+ else:
681
+ chi2_config = (100, 0.99)
682
+
683
+ tree_binning = False
684
+ if tree_binning_seed:
685
+ tree_binning = True
686
+
687
+ from Modeling_Tool.Eval.Model_Eval_Tool import get_gains_table
688
+
689
+ gains_table = get_gains_table(
690
+ data=data,
691
+ score=var,
692
+ dep=dep,
693
+ nbins=nbins,
694
+ precision=precision,
695
+ min_bin_prop=min_bin_prop,
696
+ include_missing=include_missing,
697
+ equal_freq=equal_freq,
698
+ chi2_method=chi2_method,
699
+ chi2_p=chi2_config[1],
700
+ tree_binning=tree_binning,
701
+ init_equi_bins=chi2_config[0],
702
+ fillna=fillna,
703
+ spec_values=spec_values,
704
+ sync_range=True,
705
+ grp_name=grp_name,
706
+ retSummary=False,
707
+ random_state=tree_binning_seed,
708
+ ascending=True,
709
+ withSummary=False
710
+ )
711
+
712
+ gains_table = gains_table.reset_index(drop=False).rename(columns={
713
+ "_bin_num": "BIN_NUM", "_bin_range": "BIN_RANGE"
714
+ })
715
+ woe_cols = ["BIN_NUM", "BIN_RANGE", "MIN", "MAX", "N", "RANK_ORDER_BUMP", "WOE", "IV", "AVG_BAD"]
716
+ if grp_name:
717
+ woe_cols += [grp_name]
718
+ woe_table = gains_table[woe_cols]
719
+ avg_bad_df = woe_table.loc[woe_table["BIN_NUM"] != "Grand Summary", :]
720
+
721
+ if include_missing:
722
+ monoto_info = is_monotonic(avg_bad_df.iloc[1:, :], "AVG_BAD")
723
+ else:
724
+ monoto_info = is_monotonic(avg_bad_df, "AVG_BAD")
725
+
726
+ dep_slope = calculate_slope_manual(avg_bad_df, "AVG_BAD")
727
+ direction = 1 if dep_slope > 0 else -1 if dep_slope < 0 else 0
728
+
729
+ if grp_name:
730
+ slope_grp = pd.DataFrame(
731
+ gains_table.groupby([grp_name]).apply(calculate_slope_manual, "AVG_BAD"),
732
+ columns=["SLOPE"]
733
+ )
734
+ grp_summary = gains_table.groupby([grp_name]).agg(
735
+ N=("N", sum), IV=("IV", sum), KS=("KS_PER_BIN", max),
736
+ BTM_LIFT=("LIFT", min), TOP_LIFT=("LIFT", max)
737
+ ).merge(slope_grp, left_index=True, right_index=True)
738
+ grp_summary['direction'] = grp_summary['SLOPE'].apply(
739
+ lambda x: 1 if x > 0 else -1 if x < 0 else 0
740
+ )
741
+ grp_woe_pvt = gains_table.pivot_table(
742
+ index=["BIN_NUM", "BIN_RANGE"],
743
+ columns=[grp_name],
744
+ values=["WOE", 'AVG_BAD']
745
+ )
746
+
747
+ return woe_table, grp_summary, grp_woe_pvt
748
+
749
+ return (woe_table, monoto_info[0], direction, dep_slope)
750
+
751
+
752
+ def plot_monotonicity_check(data, column, title=None, include_missing=True):
753
+ """绘制序列并标注其单调性。
754
+
755
+ 创建折线图可视化指定列的值分布,
756
+ 并在图上标注单调性检验结果。
757
+
758
+ 参数:
759
+ -----------
760
+ data : pd.DataFrame
761
+ 包含数据的数据框
762
+ column : str
763
+ 要绑制的列名
764
+ title : str, optional
765
+ 图表标题,默认为None(自动生成)
766
+ include_missing : bool, optional
767
+ 是否包含缺失值处理,默认为True
768
+
769
+ 返回:
770
+ --------
771
+ None
772
+ 直接显示图表
773
+
774
+ 示例:
775
+ --------
776
+ >>> plot_monotonicity_check(df, 'woe_values')
777
+ """
778
+ import matplotlib.pyplot as plt
779
+
780
+ series = data[column]
781
+
782
+ # 检查单调性
783
+ if include_missing:
784
+ is_mono, direction = is_monotonic(
785
+ data.iloc[1:, :], "AVG_BAD", strict=True, handle_nan='drop'
786
+ )
787
+ else:
788
+ is_mono, direction = is_monotonic(data, "AVG_BAD", strict=True, handle_nan='drop')
789
+
790
+ # 创建图表
791
+ plt.figure(figsize=(10, 6))
792
+ plt.plot(series.index, series.values, 'bo-', linewidth=2, markersize=6)
793
+
794
+ # 添加标题和标签
795
+ if title is None:
796
+ title = f"Monotonicity Check: {'Strict' if is_mono else 'Not'} Monotonic {direction if is_mono else ''}"
797
+ plt.title(title, fontsize=14)
798
+ plt.xlabel('Index')
799
+ plt.ylabel('Value')
800
+
801
+ # 添加网格
802
+ plt.grid(True, alpha=0.3)
803
+
804
+ # 显示单调性信息
805
+ plt.text(
806
+ 0.02, 0.98,
807
+ f"Strict Monotonic: {is_mono}\n Direction: {direction}",
808
+ transform=plt.gca().transAxes,
809
+ verticalalignment='top',
810
+ bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8)
811
+ )
812
+
813
+ plt.tight_layout()
814
+ plt.show()
815
+
816
+
817
+ def woe_transform(train_df, var, dep, nbins, oot_df=None, chi2_config=None, tree_binning_seed=None,
818
+ precision=5, min_bin_prop=0.05, include_missing=False, equal_freq=True,
819
+ ascending=True, fillna=-999999, spec_values=None, drop_bin_info=True,
820
+ ret_woe_table=True, check_monotonicity=False):
821
+ """将变量转换为WOE值。
822
+
823
+ 对单个变量进行分箱并计算WOE值,支持训练集和验证集的转换。
824
+ 基于WOETransformer类实现。
825
+
826
+ 参数:
827
+ -----------
828
+ train_df : pd.DataFrame
829
+ 训练数据集
830
+ var : str
831
+ 待转换的变量名
832
+ dep : str
833
+ 目标变量(因变量)名
834
+ nbins : int
835
+ 分箱数量
836
+ oot_df : pd.DataFrame, optional
837
+ 验证/测试数据集,默认为None
838
+ chi2_config : tuple, optional
839
+ 卡方分箱配置,(init_bins, p_value)元组,默认为None
840
+ tree_binning_seed : int, optional
841
+ 决策树分箱随机种子,默认为None
842
+ precision : int, optional
843
+ 计算精度,默认为5
844
+ min_bin_prop : float, optional
845
+ 每个分箱的最小样本比例,默认为0.05
846
+ include_missing : bool, optional
847
+ 是否将缺失值作为单独分箱,默认为False
848
+ equal_freq : bool, optional
849
+ 是否使用等频分箱,默认为True
850
+ ascending : bool, optional
851
+ 是否升序排列,默认为True
852
+ fillna : int/float, optional
853
+ 缺失值填充值,默认为-999999
854
+ spec_values : list, optional
855
+ 特殊值列表,默认为None
856
+ drop_bin_info : bool, optional
857
+ 是否删除中间分箱信息列,默认为True
858
+ ret_woe_table : bool, optional
859
+ 是否返回WOE映射表,默认为True
860
+ check_monotonicity : bool, optional
861
+ 是否检查单调性,默认为False
862
+
863
+ 返回:
864
+ --------
865
+ tuple/list/pd.DataFrame
866
+ 根据参数返回不同的组合:
867
+ - ret_woe_table=True, oot_df=None: (train_res, train_woe_table)
868
+ - ret_woe_table=True, oot_df不为None: (train_res, oot_res, train_woe_table)
869
+ - ret_woe_table=False, oot_df不为None: (train_res, oot_res)
870
+ - ret_woe_table=False, oot_df=None: train_res
871
+
872
+ 示例:
873
+ --------
874
+ >>> train_res, woe_table = woe_transform(df, 'age', 'target', nbins=10)
875
+ """
876
+ if spec_values is None:
877
+ spec_values = []
878
+
879
+ transformer = WOETransformer(
880
+ nbins=nbins,
881
+ precision=precision,
882
+ min_bin_prop=min_bin_prop,
883
+ include_missing=include_missing,
884
+ equal_freq=equal_freq,
885
+ fillna=fillna,
886
+ chi2_config=chi2_config,
887
+ tree_binning_seed=tree_binning_seed,
888
+ spec_values=spec_values,
889
+ drop_bin_info=drop_bin_info,
890
+ ret_woe_table=ret_woe_table
891
+ )
892
+ return transformer.transform_single(
893
+ train_df=train_df,
894
+ var=var,
895
+ dep=dep,
896
+ oot_df=oot_df,
897
+ check_monotonicity_flag=check_monotonicity
898
+ )
899
+
900
+
901
+ def woe_transformation(train_df, varlist, dep, oot_df=None, nbins=10, chi2_config=None,
902
+ tree_binning_seed=None, precision=5, min_bin_prop=0.05,
903
+ include_missing=False, equal_freq=True, fillna=-999999,
904
+ spec_values=None, drop_bin_info=True, ret_woe_table=True):
905
+ """对变量列表进行WOE转换。
906
+
907
+ 批量对多个变量进行WOE分箱和转换,支持训练集和验证集。
908
+ 基于WOETransformer类实现。
909
+
910
+ 参数:
911
+ -----------
912
+ train_df : pd.DataFrame
913
+ 训练数据集
914
+ varlist : list
915
+ 待转换的变量名列表
916
+ dep : str
917
+ 目标变量(因变量)名
918
+ oot_df : pd.DataFrame, optional
919
+ 验证/测试数据集,默认为None
920
+ nbins : int, optional
921
+ 分箱数量,默认为10
922
+ chi2_config : tuple, optional
923
+ 卡方分箱配置,(init_bins, p_value)元组,默认为None
924
+ tree_binning_seed : int, optional
925
+ 决策树分箱随机种子,默认为None
926
+ precision : int, optional
927
+ 计算精度,默认为5
928
+ min_bin_prop : float, optional
929
+ 每个分箱的最小样本比例,默认为0.05
930
+ include_missing : bool, optional
931
+ 是否将缺失值作为单独分箱,默认为False
932
+ equal_freq : bool, optional
933
+ 是否使用等频分箱,默认为True
934
+ fillna : int/float, optional
935
+ 缺失值填充值,默认为-999999
936
+ spec_values : list, optional
937
+ 特殊值列表,默认为None
938
+ drop_bin_info : bool, optional
939
+ 是否删除中间分箱信息列,默认为True
940
+ ret_woe_table : bool, optional
941
+ 是否返回WOE映射表,默认为True
942
+
943
+ 返回:
944
+ --------
945
+ tuple
946
+ (结果字典, train_woe_table) 元组。
947
+ 结果字典包含'TRAIN'键,验证集通过'OOT'键(当oot_df不为None时)
948
+
949
+ 示例:
950
+ --------
951
+ >>> result, woe_table = woe_transformation(df, ['var1', 'var2'], 'target')
952
+ """
953
+ if spec_values is None:
954
+ spec_values = []
955
+
956
+ transformer = WOETransformer(
957
+ nbins=nbins,
958
+ precision=precision,
959
+ min_bin_prop=min_bin_prop,
960
+ include_missing=include_missing,
961
+ equal_freq=equal_freq,
962
+ fillna=fillna,
963
+ chi2_config=chi2_config,
964
+ tree_binning_seed=tree_binning_seed,
965
+ spec_values=spec_values,
966
+ drop_bin_info=drop_bin_info,
967
+ ret_woe_table=ret_woe_table
968
+ )
969
+ return transformer.transform(train_df, varlist, dep, oot_df)
970
+
971
+
972
+ def _mapping_woe_single_var(data, var, woe_mapping_table, suffix="_woe", drop_bin_info=True):
973
+ """基于WOE映射表为单个变量映射WOE值。
974
+
975
+ 使用预计算的WOE映射表对新数据进行转换,
976
+ 验证单调性并检查映射结果。
977
+
978
+ 参数:
979
+ -----------
980
+ data : pd.DataFrame
981
+ 输入的数据框
982
+ var : str
983
+ 待映射的变量名
984
+ woe_mapping_table : pd.DataFrame
985
+ WOE映射表
986
+ suffix : str, optional
987
+ 变量名后缀,默认为'_woe'
988
+ drop_bin_info : bool, optional
989
+ 是否删除中间分箱信息列,默认为True
990
+
991
+ 返回:
992
+ --------
993
+ pd.DataFrame
994
+ 映射后的数据框
995
+
996
+ 注意:
997
+ --------
998
+ 当映射失败时会输出警告信息
999
+ """
1000
+ # from Modeling_Tool.Modeling_Tool.Model_Eval_Tool import run_binning
1001
+ # from 代码优化.Model_Eval_Tool import get_bin_range_list
1002
+
1003
+ left = woe_mapping_table.loc[woe_mapping_table["VAR"] == var, "BIN_RANGE"].str[0].unique()[0]
1004
+ right = woe_mapping_table.loc[woe_mapping_table["VAR"] == var, "BIN_RANGE"].str[-1].unique()[0]
1005
+
1006
+ include_lowest = False if left == '(' else True
1007
+ right = False if right == ')' else True
1008
+
1009
+ var_woe_mapping = woe_mapping_table.query(f"VAR == '{var}'")
1010
+ var_woe_mapping = var_woe_mapping[["BIN_NUM", "BIN_RANGE", "WOE", "N"]]
1011
+ bin_range = get_bin_range_list(var_woe_mapping, col="BIN_RANGE")
1012
+ woe_mapping_dict = dict(zip(var_woe_mapping['BIN_RANGE'], var_woe_mapping['WOE']))
1013
+
1014
+ res, edges = run_binning(
1015
+ data=data,
1016
+ column=var,
1017
+ nbins=sorted(set(list(bin_range) + [-np.inf, np.inf])),
1018
+ include_missing=True,
1019
+ equal_freq=True,
1020
+ bin_colnames=(f"_BIN_NUM_", f"_BIN_RANGE_"),
1021
+ ascending=True,
1022
+ include_lowest=include_lowest,
1023
+ right=right
1024
+ )
1025
+
1026
+ res[f"{var}{suffix}"] = res["_BIN_RANGE_"].map(woe_mapping_dict)
1027
+
1028
+ res_woe_table = res.groupby(["_BIN_RANGE_"]).agg(
1029
+ {f"_BIN_RANGE_": "count", var: [min, max], f"{var}{suffix}": [min, max, "mean"]}
1030
+ )
1031
+
1032
+ check_res = res_woe_table.dropna()
1033
+ assert (check_res[(f"{var}{suffix}", "min")] == check_res[(f"{var}{suffix}", "max")]).all(), \
1034
+ f"Error occurred when mapping var: {var}{suffix}"
1035
+ assert data.shape[0] == res.shape[0]
1036
+
1037
+ missing_woe = pd.isnull(res[var + suffix]).sum() > 0
1038
+ if missing_woe:
1039
+ logging.warning(f"WARNING: Failed to Map WOE values for {pd.isnull(res[var + suffix]).sum()} Records!")
1040
+
1041
+ woe = pd.DataFrame(
1042
+ res_woe_table.loc[
1043
+ res_woe_table[(var, "min")] != res_woe_table[(var, "max")],
1044
+ (f"{var}_woe", "mean")
1045
+ ]
1046
+ )
1047
+ monotonicity = is_monotonic(woe, (f"{var}_woe", "mean"))
1048
+
1049
+ if monotonicity[0]:
1050
+ logging.warning(f"WARNING: {var} WOE values are NOT monotonic in the given Dataset!")
1051
+
1052
+ if drop_bin_info:
1053
+ res = res.drop(columns=["_BIN_NUM_", "_BIN_RANGE_"])
1054
+
1055
+ return res
1056
+
1057
+
1058
+ def mapping_woe(data, varlist, woe_mapping_table, suffix="_woe", drop_bin_info = True):
1059
+ """基于WOE映射表批量映射WOE值。
1060
+
1061
+ 使用预计算的WOE映射表对多个变量进行WOE转换。
1062
+
1063
+ 参数:
1064
+ -----------
1065
+ data : pd.DataFrame
1066
+ 输入的数据框
1067
+ varlist : list
1068
+ 待映射的变量名列表
1069
+ woe_mapping_table : pd.DataFrame
1070
+ WOE映射表
1071
+ suffix : str, optional
1072
+ 变量名后缀,默认为'_woe'
1073
+ drop_bin_info : bool, optional
1074
+ 是否删除中间分箱信息列,默认为True
1075
+
1076
+ 返回:
1077
+ --------
1078
+ pd.DataFrame
1079
+ 映射后的数据框
1080
+
1081
+ 示例:
1082
+ --------
1083
+ >>> result = mapping_woe(df, ['var1', 'var2'], woe_table)
1084
+ """
1085
+ transformer = WOEMappingTransformer(
1086
+ woe_mapping_table=woe_mapping_table,
1087
+ suffix=suffix
1088
+ # drop_bin_info=drop_bin_info
1089
+ )
1090
+ res = data.copy()
1091
+ for var in varlist:
1092
+ res = _mapping_woe_single_var(data=res, var=var, woe_mapping_table=woe_mapping_table,
1093
+ suffix=suffix, drop_bin_info=drop_bin_info)
1094
+ return res