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,41 @@
1
+ # =============================================================================
2
+ # Modeling_Tool.WOE.WOE_Tool
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-WOETOOL-e00cc2c4
12
+ # (Unique trace marker. Do not remove or alter — used for plagiarism
13
+ # detection across the public internet.)
14
+ # =============================================================================
15
+
16
+ import numpy as np
17
+ import pandas as pd
18
+ import logging
19
+ from Modeling_Tool.Core.Binning_Tool import run_binning, super_binning, get_bin_range_list
20
+ from Modeling_Tool.Core.Slope_Tool import calculate_slope_manual
21
+ from Modeling_Tool.Core.utils import calc_iv, calc_woe
22
+ def is_monotonic(data, column, direction = 'auto', strict = False, handle_nan = 'drop'): ...
23
+ def check_monotonicity(data, var): ...
24
+
25
+ class WOETransformer:
26
+ def __init__(self, nbins = 10, precision = 5, min_bin_prop = 0.05, include_missing = False, equal_freq = True, fillna = -999999, chi2_config = None, tree_binning_seed = None, spec_values = None, drop_bin_info = True, ret_woe_table = True): ...
27
+ def _get_woe_table(self, binning_res, var, dep): ...
28
+ def transform_single(self, train_df, var, dep, oot_df = None, check_monotonicity_flag = False): ...
29
+ def transform(self, train_df, varlist, dep, oot_df = None, check_monotonicity_flag = False): ...
30
+ def convert_single_var_woe(data, var, woe_mapping_table, missing_ref = None, ret_bin_no = False): ...
31
+
32
+ class WOEMappingTransformer:
33
+ def __init__(self, woe_mapping_table, missing_ref = None, ret_bin_no = False, ret_category = False, rename_orig_var = False, suffix = ''): ...
34
+ def transform_single(self, data, var): ...
35
+ def transform(self, data, varlist): ...
36
+ def woe_transform_cdaml(data, varlist, woe_mapping_path, missing_ref = None, ret_bin_no = False, ret_category = False, rename_orig_var = False, suffix = ''): ...
37
+ def get_woe_table(data, var, dep, grp_name = None, nbins = 10, precision = 5, min_bin_prop = 0.05, include_missing = True, equal_freq = True, fillna = -999999, chi2_config = None, tree_binning_seed = None, spec_values = None): ...
38
+ def plot_monotonicity_check(data, column, title = None, include_missing = True): ...
39
+ def woe_transform(train_df, var, dep, nbins, oot_df = None, chi2_config = None, tree_binning_seed = None, precision = 5, min_bin_prop = 0.05, include_missing = False, equal_freq = True, ascending = True, fillna = -999999, spec_values = None, drop_bin_info = True, ret_woe_table = True, check_monotonicity = False): ...
40
+ def woe_transformation(train_df, varlist, dep, oot_df = None, nbins = 10, chi2_config = None, tree_binning_seed = None, precision = 5, min_bin_prop = 0.05, include_missing = False, equal_freq = True, fillna = -999999, spec_values = None, drop_bin_info = True, ret_woe_table = True): ...
41
+ def mapping_woe(data, varlist, woe_mapping_table, suffix = '_woe', drop_bin_info = True): ...
@@ -0,0 +1,86 @@
1
+ from .WOE_Master import (
2
+ WOE_Master,
3
+ get_overall_woe_table,
4
+ get_group_woe_table,
5
+ load_mapping_table,
6
+ get_mapping_table,
7
+ save_mapping_table,
8
+ transform,
9
+ plot_bivar_graph_func,
10
+ )
11
+
12
+ from .WOE_Plot_Tool import (
13
+ WOEPlotter,
14
+ WOEAnalyzer,
15
+ plot_woe,
16
+ plot_woe_group,
17
+ get_bivar_graph,
18
+ get_woe_table as get_woe_table_from_binning,
19
+ get_mapped_woe_summary_single,
20
+ get_mapped_woe_summary_grp,
21
+ get_mapped_woe_summary,
22
+ align_bin_num,
23
+ )
24
+
25
+ from .WOE_Tool import (
26
+ is_monotonic,
27
+ check_monotonicity,
28
+ WOETransformer,
29
+ WOEMappingTransformer,
30
+ convert_single_var_woe,
31
+ woe_transform_cdaml,
32
+ get_woe_table,
33
+ plot_monotonicity_check,
34
+ woe_transform,
35
+ woe_transformation,
36
+ mapping_woe,
37
+ )
38
+
39
+ from .WOE_Report_Builder import (
40
+ get_woe_plot_report_new,
41
+ )
42
+
43
+ from .WOE_Monotone_Binner import (
44
+ MonotoneWOEBinner,
45
+ )
46
+
47
+ from .WOE_Adapter import (
48
+ WOEEngineAdapter,
49
+ WOEMasterAdapter,
50
+ MonotoneBinnerAdapter,
51
+ as_woe_engine,
52
+ )
53
+
54
+ from .plot_woe_tool import (
55
+ extract_group_value,
56
+ cre_psi_table,
57
+ )
58
+
59
+ __all__ = [
60
+ # WOE_Master
61
+ 'WOE_Master', 'get_overall_woe_table', 'get_group_woe_table',
62
+ 'load_mapping_table', 'get_mapping_table', 'save_mapping_table',
63
+ 'transform', 'plot_bivar_graph_func',
64
+
65
+ # WOE_Plot_Tool
66
+ 'WOEPlotter', 'WOEAnalyzer', 'plot_woe', 'plot_woe_group',
67
+ 'get_bivar_graph', 'get_woe_table_from_binning',
68
+ 'get_mapped_woe_summary_single', 'get_mapped_woe_summary_grp',
69
+ 'get_mapped_woe_summary', 'align_bin_num',
70
+
71
+ # WOE_Tool
72
+ 'is_monotonic', 'check_monotonicity', 'WOETransformer',
73
+ 'WOEMappingTransformer', 'convert_single_var_woe',
74
+ 'woe_transform_cdaml', 'get_woe_table', 'plot_monotonicity_check',
75
+ 'woe_transform', 'woe_transformation', 'mapping_woe',
76
+
77
+ # WOE_Report_Builder
78
+ 'get_woe_plot_report_new',
79
+
80
+ # WOE_Monotone_Binner / adapters
81
+ 'MonotoneWOEBinner', 'WOEEngineAdapter', 'WOEMasterAdapter',
82
+ 'MonotoneBinnerAdapter', 'as_woe_engine',
83
+
84
+ # plot_woe_tool
85
+ 'extract_group_value', 'cre_psi_table',
86
+ ]
@@ -0,0 +1,290 @@
1
+ # coding: utf-8
2
+
3
+ import os
4
+ import pandas as pd
5
+ import numpy as np
6
+ from matplotlib.font_manager import FontProperties
7
+ import matplotlib.pyplot as plt
8
+ # Fix: calc_iv was used below without being imported — bug latent under pure
9
+ # Python (NameError on first call), exposed at compile time by Cython.
10
+ from Modeling_Tool.Core.utils import calc_iv
11
+ zhfont = FontProperties(fname=os.path.join(os.path.dirname(__file__), "../ref_font/KaiTi.ttf"))
12
+
13
+ palette = {
14
+ "single_01": ["#0099CC", "#FF6666", ],
15
+ "grey": "#000000", # 黑灰色
16
+ "blue": "#336699", # 蓝色
17
+ "red_list" : ["#CC0033", "#CC3333", "#FF6666", ], # 红色系由深至浅
18
+ }
19
+
20
+ def extract_group_value(woe_grp_df, value_name="lift"):
21
+ """获取指标值矩阵.
22
+
23
+ Parameters
24
+ ----------
25
+ woe_grp_df : pandas.DataFrame
26
+ 分组WOE表
27
+ value_name : str, default lift
28
+ 指标名称, 候选值"p", "p1"
29
+
30
+ Returns
31
+ -------
32
+ value_df: pandas.DataFrame
33
+ """
34
+ value_df = pd.pivot_table(woe_grp_df, index=["Var_Name", "Bin_No", "Bin_Value"], columns="Group_Name", values=value_name)
35
+
36
+ return value_df
37
+
38
+
39
+ def cre_psi_table(woe_grp_df, exp_values, value_name="p"):
40
+ """计算psi值
41
+ psi = sum((a - e) * ln(a / e))
42
+
43
+ Parameters
44
+ ----------
45
+ woe_grp_df : pandas.DataFrame
46
+ 分组WOE表
47
+ exp_values : array like
48
+ 期望值序列
49
+ value_name : str, default p
50
+ psi计算字段, 候选值"p", "p1"
51
+
52
+ Returns
53
+ -------
54
+ psi: float
55
+ """
56
+ value_df = extract_group_value(woe_grp_df, value_name)
57
+ psi_df = {}
58
+ for g in value_df.columns:
59
+ components = []
60
+ for actual, expected in zip(value_df[g], exp_values):
61
+ pair = pd.DataFrame(
62
+ {"actual": [actual], "expected": [expected]}
63
+ )
64
+ components.append(
65
+ calc_iv(pair, "actual", "expected").iloc[0]
66
+ )
67
+ psi_df.update({g: components}) # psi计算函数与iv相同
68
+ psi_df = pd.DataFrame(psi_df, index=value_df.reset_index()['Bin_Value'])
69
+ psi_df.loc["psi"] = psi_df.apply(sum)
70
+ psi_df.loc[:, "avg_psi"] = psi_df.apply(np.mean, axis=1)
71
+
72
+ return psi_df
73
+
74
+
75
+ def plot_woe(woe_df, var_rename = None, to_show=True, save_dir=None):
76
+ """绘制变量的WOE图.
77
+
78
+ Parameters
79
+ ----------
80
+ woe_df: pandas.DataFrame
81
+ WOE表
82
+ var_rename: str, default Non
83
+ 变量重命名
84
+ to_show: bool, default True
85
+ 是否展示图片
86
+ save_dir: str, default None
87
+ 结果图片存放的文件夹
88
+ """
89
+ var_name = woe_df["Var_Name"].iloc[0]
90
+ iv = round(sum(woe_df["iv"]), 5)
91
+ X = woe_df["Bin_No"]
92
+ xticks_list = [str(x)[:20]+"..." if len(str(x)) > 20 else str(x) for x in woe_df["Bin_Value"]]
93
+
94
+ # 创建画布
95
+ plt.figure(figsize=(12, 5), dpi=200) # 8,4
96
+ grid = plt.GridSpec(1, 12, wspace=0.5, hspace=0.5)
97
+
98
+ # 1.绘制Woe图
99
+ ax1 = plt.subplot(grid[:, :5])
100
+ # 绘制主坐标轴
101
+ ax1.bar(X, woe_df["p"], color=palette["single_01"][0], label="0", align="edge", width=0.985, alpha=0.8)
102
+ ax1.bar(X, woe_df["p"] * woe_df["tr"], color=palette["single_01"][1], label="1", align="edge", width=0.985)
103
+
104
+ plt.xticks(X+0.5, xticks_list, fontsize=6)
105
+ plt.yticks(fontsize=6)
106
+ ax1.axis(ymin=0.0, ymax=1)
107
+ ax1.set_ylabel("Proportion", fontsize=6)
108
+ ax1.legend(loc=2, fontsize=6)
109
+
110
+ # 绘制次坐标轴
111
+ ax1_2 = plt.twinx()
112
+ plt.axis(ymin=np.min([-1, woe_df["woe"].min() * 1.1]), ymax=np.max([1, woe_df["woe"].max() * 1.1])) # 设置次轴区间
113
+ plt.plot(X+0.5, woe_df["woe"], color="black", linewidth=1.5)
114
+ for x, woe, tr in zip(X, woe_df["woe"], woe_df["tr"]):
115
+ ax1_2.annotate(f"{woe:.3f} ({tr:.2%})",
116
+ xy=(x+0.5, woe),
117
+ va="center",
118
+ ha="center",
119
+ bbox={"boxstyle": "round", "fc": "w"},
120
+ fontsize=7
121
+ )
122
+ plt.yticks(fontsize=6)
123
+ ax1_2.set_ylabel("Woe (TargetRate)", fontsize=6)
124
+
125
+ # 绘制标题
126
+ if bool(var_rename):
127
+ plt.title(f"{str(var_rename)}: IV={iv:.3f}", fontsize=12, fontproperties=zhfont)
128
+ else:
129
+ plt.title(f"{var_name}: IV={iv:.3f}", fontsize=12, fontproperties=zhfont)
130
+
131
+ # 2.绘制Woe表
132
+ ax2 = plt.subplot(grid[:, 7:])
133
+ ax2.set_axis_off()
134
+ # plt.subplots_adjust(left=0.2, bottom=0.2)
135
+
136
+ # 调整要展示的数据
137
+ tbl = woe_df[["n", "p", "tr", "lift", "woe",]].copy()
138
+ tbl.loc["total"] = [tbl["n"].sum(), tbl["p"].sum(), woe_df["n1"].sum()/woe_df["n"].sum(), 1, 0]
139
+ tbl["n"] = [f"{x:,.0f}" for x in tbl["n"]]
140
+ tbl["p"] = [f"{x:.2%}" for x in tbl["p"]]
141
+ tbl["tr"] = [f"{x:.2%}" for x in tbl["tr"]]
142
+ tbl["lift"] = [f"{x:.2}" for x in tbl["lift"]]
143
+ tbl["woe"] = [f"{x:.3f}" for x in tbl["woe"]]
144
+
145
+ # 绘制表格
146
+ rowls = xticks_list
147
+ rowls.append("total")
148
+ tbl = ax2.table(
149
+ cellText=tbl[["n", "p", "tr", "lift", "woe"]].values,
150
+ colLabels=["N", "Prop", "TargetRate", "Lift", "WOE"],
151
+ rowLabels=rowls,
152
+ colWidths=[0.2]*5,
153
+ # rowHeights=[0.1]*len(xticks_list),
154
+ loc="center",
155
+ cellLoc="right",
156
+ rowLoc="right",
157
+ colLoc="center",
158
+ colColours=["#CCCCCC"]*5,
159
+ rowColours=["#CCCCCC"]*len(rowls),
160
+ )
161
+
162
+ tbl.scale(1, 1.5)
163
+ for key, cell in tbl.get_celld().items():
164
+ row, col = key
165
+ if row == 0 or col == -1:
166
+ cell.set_text_props(font=zhfont, fontsize=7, fontstyle="oblique")
167
+ if row > 0 and col > -1:
168
+ cell.set_text_props(font=zhfont, fontsize=7)
169
+
170
+ # 保存结果
171
+ if bool(save_dir):
172
+ plt.savefig(os.path.join(save_dir, f"{var_name}.png"), bbox_inches="tight")
173
+
174
+ # 展示结果
175
+ if to_show:
176
+ plt.show()
177
+ plt.close()
178
+
179
+
180
+ def plot_woe_group(woe_grp_df, var_rename = None, to_show=True, save_dir=None):
181
+ """绘制变量的分组WOE图.
182
+
183
+ Parameters
184
+ ----------
185
+ woe_grp_df: pandas.DataFrame
186
+ 分组WOE表
187
+ var_rename : str, default None
188
+ 变量重命名
189
+ to_show: bool, default True
190
+ 是否展示图片
191
+ save_dir: str, default None
192
+ 结果图片存放的文件夹
193
+ """
194
+ var_name = woe_grp_df["Var_Name"].iloc[0]
195
+ summary_df = woe_grp_df.groupby(["Group_Name"]).agg({"iv": sum, "n": sum, "n1": sum})
196
+ summary_df["tr"] = summary_df["n1"] / summary_df["n"]
197
+
198
+ iv_dict = {x: round(y, 5) for x, y in zip(summary_df.index, summary_df["iv"])}
199
+ tr_dict = {x: round(y, 5) for x, y in zip(summary_df.index, summary_df["tr"])}
200
+ N_dict = {x: y for x, y in zip(summary_df.index, summary_df["n"])}
201
+ X = woe_grp_df["Bin_No"].drop_duplicates()
202
+ Xticks = woe_grp_df.groupby(["Bin_No"]).agg({"Bin_Value": max})["Bin_Value"]
203
+
204
+ gs = list(set(woe_grp_df["Group_Name"]))
205
+ gs.sort()
206
+ n = len(gs)
207
+
208
+ # 构建画布
209
+ plt.figure(figsize=(12, 5), dpi=200) # 8,4
210
+ grid = plt.GridSpec(1, 12, wspace=0.5, hspace=0.5)
211
+
212
+ # 1.绘制Woe图
213
+ ax1 = plt.subplot(grid[:, :5])
214
+
215
+ # 绘制主坐标轴
216
+ width = 0.9 / n
217
+ alpha = 0.5 / n
218
+ for i in range(n):
219
+ g = gs[i]
220
+ df_plot = woe_grp_df.loc[woe_grp_df["Group_Name"] == g, ].reset_index(drop=True)
221
+ ax1.bar(X + i * (0.01 + width), df_plot["p"], color=palette["single_01"][0], label=f"{g} N={N_dict[g]:,.0f} TR={tr_dict[g]:.2%}", align="edge", width=width, alpha=0.5 + alpha*(i+1))
222
+ ax1.bar(X + i * (0.01 + width), df_plot["p"] * df_plot["tr"], color=palette["red_list"][2], align="edge", width=width, alpha=1)
223
+
224
+ xticks_list = [str(x)[:20]+"..." if len(str(x)) > 20 else str(x) for x in Xticks]
225
+ plt.xticks(X+0.5, xticks_list, fontsize=6)
226
+ plt.axis(ymin=0.0, ymax=1)
227
+ plt.yticks(fontsize=6)
228
+ plt.ylabel("Proportion", fontsize=6)
229
+ plt.legend(loc=2, fontsize=6)
230
+
231
+ # 绘制次坐标轴
232
+ alpha = 0.8 / n
233
+ ax1_2 = plt.twinx()
234
+ for i in range(n):
235
+ g = gs[i]
236
+ df_plot = woe_grp_df.loc[woe_grp_df["Group_Name"] == g, ].reset_index(drop=True)
237
+ plt.plot(X+0.5, df_plot["woe"], color=palette["grey"], linewidth=1, label=f"{g} IV={iv_dict[g]:.2f}", alpha=0.2 + alpha*(i+1))
238
+ plt.axis(ymin=np.min([-1, woe_grp_df["woe"].min() * 1.1]), ymax=np.max([1, woe_grp_df["woe"].max() * 1.1])) # 设置次轴区间
239
+ plt.yticks(fontsize=6)
240
+ plt.ylabel("Woe", fontsize=6)
241
+ plt.legend(loc=1, fontsize=6)
242
+
243
+ # 绘制总标题
244
+ if bool(var_rename):
245
+ plt.title(f"{str(var_rename)}: IV_range={summary_df.iv.min():.2f}-{summary_df.iv.max():.2f}", fontsize=12, fontproperties=zhfont)
246
+ else:
247
+ plt.title(f"{var_name}: IV_range={summary_df.iv.min():.2f}-{summary_df.iv.max():.2f}", fontsize=12, fontproperties=zhfont)
248
+
249
+ # 2.绘制Woe表
250
+ ax2 = plt.subplot(grid[:, 7:])
251
+ ax2.set_axis_off()
252
+
253
+ # 调整要展示的数据
254
+ tbl = pd.DataFrame()
255
+ for i in range(n):
256
+ g = gs[i]
257
+ tbl.loc[:, g] = woe_grp_df.loc[woe_grp_df["Group_Name"] == g, "woe"]
258
+ tbl.loc[:, g] = [f"{x:.3f}" for x in tbl[g]]
259
+
260
+ # 绘制表格
261
+ rowls = xticks_list
262
+ colls = ["_".join([x, "woe"]) for x in gs]
263
+ tbl = ax2.table(
264
+ cellText=tbl.values,
265
+ colLabels=colls,
266
+ rowLabels=rowls,
267
+ colWidths=[1.0 / n] * n,
268
+ loc="center",
269
+ cellLoc="right",
270
+ rowLoc="right",
271
+ colLoc="center",
272
+ colColours=["#CCCCCC"] * n,
273
+ rowColours=["#CCCCCC"] * len(rowls),
274
+ )
275
+ tbl.scale(1, 1.5)
276
+ for key, cell in tbl.get_celld().items():
277
+ row, col = key
278
+ if row == 0 or col == -1:
279
+ cell.set_text_props(font=zhfont, fontsize=7, fontstyle="oblique")
280
+ if row > 0 and col > -1:
281
+ cell.set_text_props(font=zhfont, fontsize=7)
282
+
283
+ # 保存结果
284
+ if bool(save_dir):
285
+ plt.savefig(os.path.join(save_dir, f"{var_name}_group.png"), bbox_inches="tight")
286
+
287
+ # 展示结果
288
+ if to_show:
289
+ plt.show()
290
+ plt.close()
@@ -0,0 +1,25 @@
1
+ # =============================================================================
2
+ # Modeling_Tool.WOE.plot_woe_tool
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-PLOTWOETOOL-98e549ad
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 matplotlib.font_manager import FontProperties
20
+ import matplotlib.pyplot as plt
21
+ from Modeling_Tool.Core.utils import calc_iv
22
+ def extract_group_value(woe_grp_df, value_name = 'lift'): ...
23
+ def cre_psi_table(woe_grp_df, exp_values, value_name = 'p'): ...
24
+ def plot_woe(woe_df, var_rename = None, to_show = True, save_dir = None): ...
25
+ def plot_woe_group(woe_grp_df, var_rename = None, to_show = True, save_dir = None): ...
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+
3
+ __author__ = "Jingkai Sun"
4
+ __version__ = "0.2.0"
5
+
6
+ # Core module - base data structures
7
+ from .Core import (
8
+ Binning,
9
+ super_binning,
10
+ SlopeCalculator,
11
+ DataFrameProcessor,
12
+ FilePathManager,
13
+ DateTimeUtils,
14
+ WOEIVCalculator,
15
+ TextEncryptor,
16
+ get_feature_names,
17
+ pull_attributes_in_batch,
18
+ save_model,
19
+ load_model,
20
+ load_model_metadata,
21
+ scoring,
22
+ )
23
+
24
+ # Evaluation module
25
+ from .Eval import (
26
+ cross_risk,
27
+ get_gains_table,
28
+ get_perf_summary,
29
+ GainsTableCalculator,
30
+ PerformanceEvaluator,
31
+ Model_Evaluation_Tool,
32
+ EvaluationPipeline,
33
+ get_gains_table_by_cust_metrics,
34
+ calc_pr,
35
+ calc_roc,
36
+ calc_lift_apt,
37
+ calc_equid_dist,
38
+ calc_equid_pct,
39
+ calc_fixed_pct,
40
+ evaluate_performance,
41
+ comparison_performance,
42
+ )
43
+
44
+ # Sample module
45
+ from .Sample import (
46
+ DistributionAdaptation,
47
+ RejectInferrer,
48
+ RejectInferenceFactory,
49
+ ParcelingInferrer,
50
+ HardCutoffInferrer,
51
+ FuzzyAugmentInferrer,
52
+ SimpleAugmentInferrer,
53
+ SampleSplitter,
54
+ StratifiedSampler,
55
+ SampleBalancer,
56
+ select_sample_seed,
57
+ )
58
+
59
+ # WOE module
60
+ from .WOE import (
61
+ WOE_Master,
62
+ MonotoneWOEBinner,
63
+ WOEEngineAdapter,
64
+ as_woe_engine,
65
+ is_monotonic,
66
+ woe_transform,
67
+ woe_transformation,
68
+ plot_woe,
69
+ save_mapping_table,
70
+ load_mapping_table,
71
+ get_overall_woe_table,
72
+ )
73
+
74
+ # Feature module
75
+ from .Feature import (
76
+ DistributionShiftAnalyzer,
77
+ DistributionPlotter,
78
+ VarExtractionInsights,
79
+ CorrelationFilter,
80
+ PSICalculator,
81
+ calculate_psi_within_dataset,
82
+ )
83
+
84
+ _MODEL_EXPORTS = frozenset({
85
+ 'GradientBoostingModel', 'LightGBMModel', 'XGBoostModel', 'CatBoostModel',
86
+ 'lgbm_quick_train', 'xgbm_quick_train', 'catboost_quick_train',
87
+ 'LRMaster', 'FeatureSelectionAnalyzer', 'BackwardVariableEliminator',
88
+ 'backward_lgbm', 'backward_xgbm',
89
+ })
90
+
91
+ _EXPLAIN_EXPORTS = frozenset({
92
+ 'ModelExplainer', 'build_coalition_structure', 'CREDIT_PRIOR_GROUPS',
93
+ })
94
+
95
+ def __getattr__(name):
96
+ if name in _MODEL_EXPORTS:
97
+ from . import Model as _Model
98
+ return getattr(_Model, name)
99
+ if name in _EXPLAIN_EXPORTS:
100
+ from . import Explainability as _explain
101
+ return getattr(_explain, name)
102
+ if name == "ODPSRunner":
103
+ from .Core import ODPSRunner
104
+ return ODPSRunner
105
+ raise AttributeError(f"module 'Modeling_Tool' has no attribute {name!r}")
106
+
107
+
108
+ __all__ = [
109
+ '__author__',
110
+ '__version__',
111
+ 'Binning',
112
+ 'super_binning',
113
+ 'ODPSRunner',
114
+ 'SlopeCalculator',
115
+ 'DataFrameProcessor',
116
+ 'FilePathManager',
117
+ 'DateTimeUtils',
118
+ 'WOEIVCalculator',
119
+ 'TextEncryptor',
120
+ 'get_feature_names',
121
+ 'pull_attributes_in_batch',
122
+ 'save_model',
123
+ 'load_model',
124
+ 'load_model_metadata',
125
+ 'scoring',
126
+ 'GradientBoostingModel',
127
+ 'LightGBMModel',
128
+ 'XGBoostModel',
129
+ 'CatBoostModel',
130
+ 'lgbm_quick_train',
131
+ 'xgbm_quick_train',
132
+ 'catboost_quick_train',
133
+ 'LRMaster',
134
+ 'FeatureSelectionAnalyzer',
135
+ 'BackwardVariableEliminator',
136
+ 'ModelExplainer',
137
+ 'build_coalition_structure',
138
+ 'CREDIT_PRIOR_GROUPS',
139
+ 'cross_risk',
140
+ 'GainsTableCalculator',
141
+ 'PerformanceEvaluator',
142
+ 'Model_Evaluation_Tool',
143
+ 'EvaluationPipeline',
144
+ 'get_gains_table_by_cust_metrics',
145
+ 'calc_lift_apt',
146
+ 'evaluate_performance',
147
+ 'comparison_performance',
148
+ 'DistributionAdaptation',
149
+ 'RejectInferrer',
150
+ 'RejectInferenceFactory',
151
+ 'ParcelingInferrer',
152
+ 'HardCutoffInferrer',
153
+ 'FuzzyAugmentInferrer',
154
+ 'SimpleAugmentInferrer',
155
+ 'SampleSplitter',
156
+ 'StratifiedSampler',
157
+ 'SampleBalancer',
158
+ 'select_sample_seed',
159
+ 'WOE_Master',
160
+ 'MonotoneWOEBinner',
161
+ 'WOEEngineAdapter',
162
+ 'as_woe_engine',
163
+ 'is_monotonic',
164
+ 'woe_transform',
165
+ 'woe_transformation',
166
+ 'plot_woe',
167
+ 'save_mapping_table',
168
+ 'load_mapping_table',
169
+ 'get_overall_woe_table',
170
+ 'DistributionShiftAnalyzer',
171
+ 'DistributionPlotter',
172
+ 'VarExtractionInsights',
173
+ 'CorrelationFilter',
174
+ 'PSICalculator',
175
+ 'calculate_psi_within_dataset',
176
+ ]