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,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
|
+
]
|