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,919 @@
|
|
|
1
|
+
from matplotlib import pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
from matplotlib.font_manager import FontProperties
|
|
8
|
+
|
|
9
|
+
from .WOE_Tool import calc_woe, calc_iv, mapping_woe
|
|
10
|
+
from Modeling_Tool.Core.utils import mkdir_if_not_exist
|
|
11
|
+
|
|
12
|
+
zhfont = FontProperties(fname=os.path.join(os.path.dirname(__file__), "../ref_font/KaiTi.ttf"))
|
|
13
|
+
palette = {
|
|
14
|
+
"single_01": ["#0099CC", "#FF6666", ],
|
|
15
|
+
"grey": "#000000", # 黑灰色
|
|
16
|
+
"blue": "#336699", # 蓝色
|
|
17
|
+
"red_list" : ["#CC0033", "#CC3333", "#FF6666", ], # 红色系由深至浅
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def plot_woe(woe_df, var_rename=None, to_show=True, save_dir=None, fig_name='var.png'):
|
|
21
|
+
"""
|
|
22
|
+
绘制变量的WOE图。
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
woe_df : pandas.DataFrame
|
|
27
|
+
WOE表,包含变量、分箱等信息
|
|
28
|
+
var_rename : str, optional
|
|
29
|
+
变量重命名,用于图表标题显示,默认为None
|
|
30
|
+
to_show : bool, optional
|
|
31
|
+
是否展示图片,默认为True
|
|
32
|
+
save_dir : str, optional
|
|
33
|
+
结果图片存放的文件夹路径,默认为None
|
|
34
|
+
fig_name : str, optional
|
|
35
|
+
保存图片的文件名,默认为'var.png'
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
None
|
|
40
|
+
函数直接绘制图表并可选保存或展示
|
|
41
|
+
|
|
42
|
+
Examples
|
|
43
|
+
--------
|
|
44
|
+
>>> plot_woe(woe_df, var_rename='年龄', save_dir='./output')
|
|
45
|
+
"""
|
|
46
|
+
woe_df.columns = [x.lower() for x in woe_df.columns]
|
|
47
|
+
woe_df[['woe', 'iv']] = woe_df[['woe', 'iv']].replace([np.inf, -np.inf], 0)
|
|
48
|
+
|
|
49
|
+
woe_res = []
|
|
50
|
+
for _, group in woe_df.groupby('var'):
|
|
51
|
+
group['p'] = group['n']/group['n'].sum()
|
|
52
|
+
woe_res.append(group)
|
|
53
|
+
woe_res = pd.concat(woe_res)
|
|
54
|
+
woe_df = woe_res.copy()
|
|
55
|
+
|
|
56
|
+
var_name = woe_df["var"].iloc[0]
|
|
57
|
+
iv = round(sum(woe_df["iv"]), 5)
|
|
58
|
+
X = woe_df["bin_num"]
|
|
59
|
+
xticks_list = [str(x)[:20]+"..." if len(str(x)) > 20 else str(x) for x in woe_df["bin_range"]]
|
|
60
|
+
|
|
61
|
+
# 创建画布
|
|
62
|
+
plt.figure(figsize=(12, 5), dpi=200) # 8,4
|
|
63
|
+
grid = plt.GridSpec(1, 12, wspace=0.5, hspace=0.5)
|
|
64
|
+
|
|
65
|
+
# 1.绘制Woe图
|
|
66
|
+
ax1 = plt.subplot(grid[:, :5])
|
|
67
|
+
# 绘制主坐标轴
|
|
68
|
+
ax1.bar(X, woe_df["p"], color=palette["single_01"][0], label="0", align="edge", width=0.985, alpha=0.8)
|
|
69
|
+
ax1.bar(X, woe_df["p"] * woe_df["avg_bad"], color=palette["single_01"][1], label="1", align="edge", width=0.985)
|
|
70
|
+
|
|
71
|
+
plt.xticks(X+0.5, xticks_list, fontsize=6, rotation=45)
|
|
72
|
+
plt.yticks(fontsize=6)
|
|
73
|
+
ax1.axis(ymin=0.0, ymax=1)
|
|
74
|
+
ax1.set_ylabel("Proportion", fontsize=6)
|
|
75
|
+
ax1.legend(loc=2, fontsize=6)
|
|
76
|
+
|
|
77
|
+
# 绘制次坐标轴
|
|
78
|
+
ax1_2 = plt.twinx()
|
|
79
|
+
plt.axis(ymin=np.min([-1, woe_df["woe"].min() * 1.1]), ymax=np.max([1, woe_df["woe"].max() * 1.1])) # 设置次轴区间
|
|
80
|
+
plt.plot(X+0.5, woe_df["woe"], color="black", linewidth=1.5)
|
|
81
|
+
for x, woe, avg_bad in zip(X, woe_df["woe"], woe_df["avg_bad"]):
|
|
82
|
+
ax1_2.annotate(f"{woe:.3f} ({avg_bad:.2%})",
|
|
83
|
+
xy=(x+0.5, woe),
|
|
84
|
+
va="center",
|
|
85
|
+
ha="center",
|
|
86
|
+
bbox={"boxstyle": "round", "fc": "w"},
|
|
87
|
+
fontsize=7
|
|
88
|
+
)
|
|
89
|
+
plt.yticks(fontsize=6)
|
|
90
|
+
ax1_2.set_ylabel("WOE (TargetRate)", fontsize=6)
|
|
91
|
+
|
|
92
|
+
# 绘制标题
|
|
93
|
+
if bool(var_rename):
|
|
94
|
+
plt.title(f"{str(var_rename)}: IV={iv:.3f}", fontsize=12, fontproperties=zhfont)
|
|
95
|
+
else:
|
|
96
|
+
plt.title(f"{var_name}: IV={iv:.3f}", fontsize=12, fontproperties=zhfont)
|
|
97
|
+
|
|
98
|
+
# 2.绘制Woe表
|
|
99
|
+
ax2 = plt.subplot(grid[:, 7:])
|
|
100
|
+
ax2.set_axis_off()
|
|
101
|
+
|
|
102
|
+
# 调整要展示的数据
|
|
103
|
+
tbl = woe_df[["n", "p", "avg_bad", "lift", "woe",]].copy()
|
|
104
|
+
tbl.loc["total"] = [tbl["n"].sum(), tbl["p"].sum(), woe_df["n_bad"].sum()/woe_df["n"].sum(), 1, 0]
|
|
105
|
+
tbl["n"] = [f"{x:,.0f}" for x in tbl["n"]]
|
|
106
|
+
tbl["p"] = [f"{x:.2%}" for x in tbl["p"]]
|
|
107
|
+
tbl["avg_bad"] = [f"{x:.2%}" for x in tbl["avg_bad"]]
|
|
108
|
+
tbl["lift"] = [f"{x:.2}" for x in tbl["lift"]]
|
|
109
|
+
tbl["woe"] = [f"{x:.3f}" for x in tbl["woe"]]
|
|
110
|
+
|
|
111
|
+
# 绘制表格
|
|
112
|
+
rowls = xticks_list
|
|
113
|
+
rowls.append("total")
|
|
114
|
+
tbl = ax2.table(
|
|
115
|
+
cellText=tbl[["n", "p", "avg_bad", "lift", "woe"]].values,
|
|
116
|
+
colLabels=["N", "Prop", "BadRate", "Lift", "WOE"],
|
|
117
|
+
rowLabels=rowls,
|
|
118
|
+
colWidths=[0.2]*5,
|
|
119
|
+
loc="center",
|
|
120
|
+
cellLoc="right",
|
|
121
|
+
rowLoc="right",
|
|
122
|
+
colLoc="center",
|
|
123
|
+
colColours=["#CCCCCC"]*5,
|
|
124
|
+
rowColours=["#CCCCCC"]*len(rowls),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
tbl.scale(1, 1.5)
|
|
128
|
+
for key, cell in tbl.get_celld().items():
|
|
129
|
+
row, col = key
|
|
130
|
+
if row == 0 or col == -1:
|
|
131
|
+
cell.set_text_props(font=zhfont, fontsize=7, fontstyle="oblique")
|
|
132
|
+
if row > 0 and col > -1:
|
|
133
|
+
cell.set_text_props(font=zhfont, fontsize=7)
|
|
134
|
+
|
|
135
|
+
# 保存结果
|
|
136
|
+
if bool(save_dir):
|
|
137
|
+
plt.savefig(os.path.join(save_dir, fig_name), bbox_inches="tight")
|
|
138
|
+
|
|
139
|
+
# 展示结果
|
|
140
|
+
if to_show:
|
|
141
|
+
plt.show()
|
|
142
|
+
plt.close()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_woe_table(binning_res, var, dep):
|
|
146
|
+
"""
|
|
147
|
+
根据分箱结果计算并返回WOE表和WOE映射字典。
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
binning_res : pandas.DataFrame
|
|
152
|
+
包含分箱结果的数据框,应包含 _bin_num_{var} 和 _bin_range_{var} 列
|
|
153
|
+
var : str
|
|
154
|
+
变量名称,用于标识要分析的特征列
|
|
155
|
+
dep : str
|
|
156
|
+
目标变量名称,用于计算好坏样本统计信息
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
tuple
|
|
161
|
+
- woe_table (pandas.DataFrame): 包含每个分箱的WOE、IV等统计信息的表格
|
|
162
|
+
- woe_mapping_dict (dict): 将分箱范围映射到WOE值的字典
|
|
163
|
+
|
|
164
|
+
Examples
|
|
165
|
+
--------
|
|
166
|
+
>>> woe_table, woe_dict = get_woe_table(binning_res, 'age', 'target')
|
|
167
|
+
"""
|
|
168
|
+
# 计算每个分箱的统计信息
|
|
169
|
+
woe_table = binning_res.groupby([f"_bin_num_{var}", f"_bin_range_{var}"], dropna = False)\
|
|
170
|
+
.agg(MIN = (var, "min"),
|
|
171
|
+
MAX = (var, "max"),
|
|
172
|
+
N = (f"_bin_num_{var}", "count"),
|
|
173
|
+
AVG_SCORE = (var, "mean"),
|
|
174
|
+
AVG_BAD = (dep, lambda x: ( (x==1).sum() / x.count()) ),
|
|
175
|
+
AVG_GOOD = (dep, lambda x: ( (x==0).sum() / x.count()) ),
|
|
176
|
+
N_BAD = (dep, "sum"),
|
|
177
|
+
N_GOOD = (dep, lambda x: (x==0).sum()))
|
|
178
|
+
|
|
179
|
+
## IV/WOE Calculation
|
|
180
|
+
woe_table["BAD_PCT_PER_BIN"] = woe_table["N_BAD"] / woe_table["N_BAD"].sum()
|
|
181
|
+
woe_table["GOOD_PCT_PER_BIN"] = woe_table["N_GOOD"] / woe_table["N_GOOD"].sum()
|
|
182
|
+
woe_table["LIFT"] = woe_table['AVG_BAD'] / woe_table['AVG_BAD'].mean()
|
|
183
|
+
woe_table["WOE"] = calc_woe(data = woe_table, bad_pct = "BAD_PCT_PER_BIN", good_pct = "GOOD_PCT_PER_BIN")
|
|
184
|
+
woe_table["IV"] = calc_iv(data = woe_table, bad_pct = "BAD_PCT_PER_BIN", good_pct = "GOOD_PCT_PER_BIN")
|
|
185
|
+
|
|
186
|
+
## WOE Mapping Dictionary
|
|
187
|
+
woe_table = woe_table.reset_index(drop=False)
|
|
188
|
+
woe_mapping_dict = dict(zip(woe_table[f"_bin_range_{var}"], woe_table["WOE"]))
|
|
189
|
+
|
|
190
|
+
return woe_table, woe_mapping_dict
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_mapped_woe_summary_single(data, var, ref_woe_table, tgt_name):
|
|
194
|
+
"""
|
|
195
|
+
根据给定的参考WOE映射表,对单个变量生成WOE汇总表。
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
data : pandas.DataFrame
|
|
200
|
+
输入数据,包含原始变量值
|
|
201
|
+
var : str
|
|
202
|
+
变量名称
|
|
203
|
+
ref_woe_table : pandas.DataFrame
|
|
204
|
+
参考WOE映射表,包含各变量的标准WOE分箱信息
|
|
205
|
+
tgt_name : str
|
|
206
|
+
目标变量名称,用于计算好坏样本比例
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
pandas.DataFrame
|
|
211
|
+
与参考WOE表格式一致的变量WOE汇总表
|
|
212
|
+
|
|
213
|
+
Examples
|
|
214
|
+
--------
|
|
215
|
+
>>> summary = get_mapped_woe_summary_single(data, 'income', ref_table, 'default')
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
ref_var_woe_table = ref_woe_table[ref_woe_table["VAR"] == var]
|
|
219
|
+
|
|
220
|
+
df_mapped = mapping_woe(data, [var.replace("_woe", "")], ref_woe_table, suffix = "_woe", drop_bin_info = False)
|
|
221
|
+
df_mapped.columns = [x.lower() for x in df_mapped.columns]
|
|
222
|
+
|
|
223
|
+
if f"_bin_num_{var}" in df_mapped.columns:
|
|
224
|
+
df_mapped = df_mapped.drop(columns = [f"_bin_num_{var}"])
|
|
225
|
+
|
|
226
|
+
if f"_bin_range_{var}" in df_mapped.columns:
|
|
227
|
+
df_mapped = df_mapped.drop(columns = [f"_bin_range_{var}"])
|
|
228
|
+
|
|
229
|
+
df_mapped = df_mapped.rename(columns = {"_bin_num_": f"_bin_num_{var}",
|
|
230
|
+
"_bin_range_": f"_bin_range_{var}"})
|
|
231
|
+
|
|
232
|
+
var_woe_table = get_woe_table(df_mapped, var, dep = tgt_name)[0]
|
|
233
|
+
var_woe_table["VAR"] = var
|
|
234
|
+
|
|
235
|
+
var_woe_table = var_woe_table.rename(columns = {f"_bin_num_{var}": "bin_num", f"_bin_range_{var}": f"bin_range"})
|
|
236
|
+
var_woe_table.columns = [x.upper() for x in var_woe_table.columns]
|
|
237
|
+
fnlcollist = ref_woe_table.columns.tolist()
|
|
238
|
+
return var_woe_table[fnlcollist]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def get_mapped_woe_summary_grp(data, var, ref_woe_table, tgt_name, grp_name=None):
|
|
242
|
+
"""
|
|
243
|
+
获取分组后的单个变量WOE汇总表。
|
|
244
|
+
|
|
245
|
+
Parameters
|
|
246
|
+
----------
|
|
247
|
+
data : pandas.DataFrame
|
|
248
|
+
输入数据,包含原始变量值和分组信息
|
|
249
|
+
var : str
|
|
250
|
+
变量名称
|
|
251
|
+
ref_woe_table : pandas.DataFrame
|
|
252
|
+
参考WOE映射表,包含各变量的标准WOE分箱信息
|
|
253
|
+
tgt_name : str
|
|
254
|
+
目标变量名称,用于计算好坏样本比例
|
|
255
|
+
grp_name : str or list, optional
|
|
256
|
+
分组字段名称,用于按组别分别计算WOE,默认为None
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
pandas.DataFrame
|
|
261
|
+
分组后的变量WOE汇总表
|
|
262
|
+
|
|
263
|
+
Notes
|
|
264
|
+
-----
|
|
265
|
+
如果数据中存在缺失值,会自动删除包含缺失值的记录并记录警告日志
|
|
266
|
+
|
|
267
|
+
Examples
|
|
268
|
+
--------
|
|
269
|
+
>>> summary = get_mapped_woe_summary_grp(data, 'age', ref_table, 'default', 'city')
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
if data.query(f"{var} != {var}").shape[0] > 0:
|
|
273
|
+
data = data.dropna(subset=[var])
|
|
274
|
+
logging.info(f"WARNING: Found Missing Value in {var}, Missing Records Had Been Dropped!")
|
|
275
|
+
|
|
276
|
+
if grp_name:
|
|
277
|
+
fnl_res = []
|
|
278
|
+
for grp, group in data.groupby(grp_name):
|
|
279
|
+
grp_res = get_mapped_woe_summary_single(data = group, var = var, ref_woe_table = ref_woe_table, tgt_name = tgt_name)
|
|
280
|
+
for i, g in enumerate(grp):
|
|
281
|
+
grp_res[grp_name[i]] = g
|
|
282
|
+
fnl_res.append(grp_res)
|
|
283
|
+
|
|
284
|
+
return pd.concat(fnl_res)
|
|
285
|
+
|
|
286
|
+
return get_mapped_woe_summary_single(data = data, var = var, ref_woe_table = ref_woe_table, tgt_name=tgt_name)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def get_mapped_woe_summary(data, ref_woe_table, tgt_name, varlist=None, grp_name=None):
|
|
290
|
+
"""
|
|
291
|
+
获取多个变量的WOE汇总表。
|
|
292
|
+
|
|
293
|
+
Parameters
|
|
294
|
+
----------
|
|
295
|
+
data : pandas.DataFrame
|
|
296
|
+
输入数据,包含原始变量值
|
|
297
|
+
ref_woe_table : pandas.DataFrame
|
|
298
|
+
参考WOE映射表,包含各变量的标准WOE分箱信息
|
|
299
|
+
tgt_name : str
|
|
300
|
+
目标变量名称,用于计算好坏样本比例
|
|
301
|
+
varlist : list, optional
|
|
302
|
+
要计算的变量列表,默认为None(使用参考表中的所有变量)
|
|
303
|
+
grp_name : str or list, optional
|
|
304
|
+
分组字段名称,用于按组别分别计算WOE,默认为None
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
pandas.DataFrame
|
|
309
|
+
包含所有变量WOE信息的汇总表
|
|
310
|
+
|
|
311
|
+
Examples
|
|
312
|
+
--------
|
|
313
|
+
>>> summary = get_mapped_woe_summary(data, ref_table, 'default', varlist=['age', 'income'])
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
if varlist is None:
|
|
317
|
+
varlist = ref_woe_table['VAR'].unique().tolist()
|
|
318
|
+
|
|
319
|
+
fnl_res = []
|
|
320
|
+
for var in varlist:
|
|
321
|
+
var_res = get_mapped_woe_summary_grp(data, var, ref_woe_table, tgt_name, grp_name)
|
|
322
|
+
fnl_res.append(var_res)
|
|
323
|
+
|
|
324
|
+
return pd.concat(fnl_res)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def plot_woe_group(woe_grp_df, grp_name=None, var_rename=None, to_show=True, save_dir=None, fig_name="var_group.png"):
|
|
328
|
+
"""
|
|
329
|
+
绘制变量的分组WOE图。
|
|
330
|
+
|
|
331
|
+
Parameters
|
|
332
|
+
----------
|
|
333
|
+
woe_grp_df : pandas.DataFrame
|
|
334
|
+
分组WOE表,包含按组别分组后的WOE信息
|
|
335
|
+
grp_name : str, optional
|
|
336
|
+
分组字段名称,用于区分不同组的WOE曲线,默认为None
|
|
337
|
+
var_rename : str, optional
|
|
338
|
+
变量重命名,用于图表标题显示,默认为None
|
|
339
|
+
to_show : bool, optional
|
|
340
|
+
是否展示图片,默认为True
|
|
341
|
+
save_dir : str, optional
|
|
342
|
+
结果图片存放的文件夹路径,默认为None
|
|
343
|
+
fig_name : str, optional
|
|
344
|
+
保存图片的文件名,默认为'var_group.png'
|
|
345
|
+
|
|
346
|
+
Returns
|
|
347
|
+
-------
|
|
348
|
+
None
|
|
349
|
+
函数直接绘制图表并可选保存或展示
|
|
350
|
+
|
|
351
|
+
Examples
|
|
352
|
+
--------
|
|
353
|
+
>>> plot_woe_group(woe_grp_df, grp_name='gender', save_dir='./output')
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
woe_grp_df.columns = [x.lower() for x in woe_grp_df.columns]
|
|
358
|
+
woe_grp_df[['woe', 'iv']] = woe_grp_df[['woe', 'iv']].replace([np.inf, -np.inf], np.nan)
|
|
359
|
+
|
|
360
|
+
var_name = woe_grp_df["var"].iloc[0]
|
|
361
|
+
summary_df = woe_grp_df.groupby([grp_name]).agg({"iv": sum, "n": sum, "n_bad": sum})
|
|
362
|
+
summary_df["avg_bad"] = summary_df["n_bad"] / summary_df["n"]
|
|
363
|
+
|
|
364
|
+
iv_dict = {x: round(y, 5) for x, y in zip(summary_df.index, summary_df["iv"])}
|
|
365
|
+
tr_dict = {x: round(y, 5) for x, y in zip(summary_df.index, summary_df["avg_bad"])}
|
|
366
|
+
N_dict = {x: y for x, y in zip(summary_df.index, summary_df["n"])}
|
|
367
|
+
X = woe_grp_df["bin_num"].drop_duplicates()
|
|
368
|
+
Xticks = woe_grp_df.groupby(["bin_num"]).agg({"bin_range": max})["bin_range"]
|
|
369
|
+
|
|
370
|
+
gs = list(set(woe_grp_df[grp_name]))
|
|
371
|
+
gs.sort()
|
|
372
|
+
n = len(gs)
|
|
373
|
+
|
|
374
|
+
# 构建画布
|
|
375
|
+
plt.figure(figsize=(12, 5), dpi=200) # 8,4
|
|
376
|
+
grid = plt.GridSpec(1, 12, wspace=0.5, hspace=0.5)
|
|
377
|
+
|
|
378
|
+
# 1.绘制Woe图
|
|
379
|
+
ax1 = plt.subplot(grid[:, :5])
|
|
380
|
+
|
|
381
|
+
# 绘制主坐标轴
|
|
382
|
+
width = 0.9 / n
|
|
383
|
+
alpha = 0.5 / n
|
|
384
|
+
for i in range(n):
|
|
385
|
+
g = gs[i]
|
|
386
|
+
df_plot = woe_grp_df.loc[woe_grp_df[grp_name] == g, ].reset_index(drop=True)
|
|
387
|
+
df_plot['p'] = df_plot['n'] / df_plot['n'].sum()
|
|
388
|
+
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))
|
|
389
|
+
ax1.bar(X + i * (0.01 + width), df_plot["p"] * df_plot["avg_bad"], color=palette["red_list"][2], align="edge", width=width, alpha=1)
|
|
390
|
+
|
|
391
|
+
xticks_list = [str(x)[:20]+"..." if len(str(x)) > 20 else str(x) for x in Xticks]
|
|
392
|
+
plt.xticks(X+0.5, xticks_list, fontsize=6, rotation=45)
|
|
393
|
+
plt.axis(ymin=0.0, ymax=1)
|
|
394
|
+
plt.yticks(fontsize=6)
|
|
395
|
+
plt.ylabel("Proportion", fontsize=6)
|
|
396
|
+
plt.legend(loc=2, fontsize=6)
|
|
397
|
+
|
|
398
|
+
# 绘制次坐标轴
|
|
399
|
+
alpha = 0.8 / n
|
|
400
|
+
ax1_2 = plt.twinx()
|
|
401
|
+
for i in range(n):
|
|
402
|
+
g = gs[i]
|
|
403
|
+
df_plot = woe_grp_df.loc[woe_grp_df[grp_name] == g, ].reset_index(drop=True)
|
|
404
|
+
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))
|
|
405
|
+
plt.axis(ymin=np.min([-1, woe_grp_df["woe"].min() * 1.1]), ymax=np.max([1, woe_grp_df["woe"].max() * 1.1])) # 设置次轴区间
|
|
406
|
+
plt.yticks(fontsize=6)
|
|
407
|
+
plt.ylabel("WOE", fontsize=6)
|
|
408
|
+
plt.legend(loc=1, fontsize=6)
|
|
409
|
+
|
|
410
|
+
# 绘制总标题
|
|
411
|
+
if bool(var_rename):
|
|
412
|
+
plt.title(f"{str(var_rename)}: IV_range={summary_df.iv.min():.2f}-{summary_df.iv.max():.2f}", fontsize=12, fontproperties=zhfont)
|
|
413
|
+
else:
|
|
414
|
+
plt.title(f"{var_name}: IV_range={summary_df.iv.min():.2f}-{summary_df.iv.max():.2f}", fontsize=12, fontproperties=zhfont)
|
|
415
|
+
|
|
416
|
+
# 2.绘制Woe表
|
|
417
|
+
ax2 = plt.subplot(grid[:, 7:])
|
|
418
|
+
ax2.set_axis_off()
|
|
419
|
+
|
|
420
|
+
# 调整要展示的数据
|
|
421
|
+
tbl = pd.DataFrame()
|
|
422
|
+
for i in range(n):
|
|
423
|
+
g = gs[i]
|
|
424
|
+
tbl.loc[:, g] = woe_grp_df.loc[woe_grp_df[grp_name] == g, "woe"]
|
|
425
|
+
tbl.loc[:, g] = [f"{x:.3f}" for x in tbl[g]]
|
|
426
|
+
|
|
427
|
+
# 绘制表格
|
|
428
|
+
rowls = xticks_list
|
|
429
|
+
colls = ["_".join([x, "woe"]) for x in gs]
|
|
430
|
+
tbl = ax2.table(
|
|
431
|
+
cellText=tbl.values,
|
|
432
|
+
colLabels=colls,
|
|
433
|
+
rowLabels=rowls,
|
|
434
|
+
colWidths=[1.0 / n] * n,
|
|
435
|
+
loc="center",
|
|
436
|
+
cellLoc="right",
|
|
437
|
+
rowLoc="right",
|
|
438
|
+
colLoc="center",
|
|
439
|
+
colColours=["#CCCCCC"] * n,
|
|
440
|
+
rowColours=["#CCCCCC"] * len(rowls),
|
|
441
|
+
)
|
|
442
|
+
tbl.scale(1, 1.5)
|
|
443
|
+
for key, cell in tbl.get_celld().items():
|
|
444
|
+
row, col = key
|
|
445
|
+
if row == 0 or col == -1:
|
|
446
|
+
cell.set_text_props(font=zhfont, fontsize=7, fontstyle="oblique")
|
|
447
|
+
if row > 0 and col > -1:
|
|
448
|
+
cell.set_text_props(font=zhfont, fontsize=7)
|
|
449
|
+
|
|
450
|
+
# 保存结果
|
|
451
|
+
if bool(save_dir):
|
|
452
|
+
plt.savefig(os.path.join(save_dir, fig_name), bbox_inches="tight")
|
|
453
|
+
|
|
454
|
+
# 展示结果
|
|
455
|
+
if to_show:
|
|
456
|
+
plt.show()
|
|
457
|
+
plt.close()
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def align_bin_num(woe_table, grp_woe_df, grp_name):
|
|
461
|
+
"""
|
|
462
|
+
对齐分组WOE表与参考WOE表的分箱编号。
|
|
463
|
+
|
|
464
|
+
Parameters
|
|
465
|
+
----------
|
|
466
|
+
woe_table : pandas.DataFrame
|
|
467
|
+
参考WOE表,包含标准的分箱定义
|
|
468
|
+
grp_woe_df : pandas.DataFrame
|
|
469
|
+
分组WOE表,需要与参考表对齐
|
|
470
|
+
grp_name : str or list
|
|
471
|
+
分组字段名称
|
|
472
|
+
|
|
473
|
+
Returns
|
|
474
|
+
-------
|
|
475
|
+
pandas.DataFrame
|
|
476
|
+
对齐后的分组WOE表,BIN_NUM重新编号以避免空值
|
|
477
|
+
|
|
478
|
+
Examples
|
|
479
|
+
--------
|
|
480
|
+
>>> aligned = align_bin_num(ref_woe_table, grp_woe_df, 'city')
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
left_data = woe_table[['BIN_RANGE', 'VAR']]
|
|
484
|
+
left_data.columns = [x.upper() for x in left_data.columns]
|
|
485
|
+
|
|
486
|
+
fnl_res = []
|
|
487
|
+
for grp, group in grp_woe_df.groupby(grp_name):
|
|
488
|
+
grp_res = left_data.merge(group, on = ['BIN_RANGE', 'VAR'], how = 'left')
|
|
489
|
+
for i, g in enumerate(grp):
|
|
490
|
+
grp_res[grp_name[i]] = g
|
|
491
|
+
|
|
492
|
+
fnl_res.append(grp_res)
|
|
493
|
+
fnl_res = pd.concat(fnl_res)
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
## Reset BIN_NUM to Avoid Null values in BIN_NUM column
|
|
497
|
+
reset_bin_num_res = []
|
|
498
|
+
for _, group_data in fnl_res.groupby(['VAR', *grp_name]):
|
|
499
|
+
group_data = group_data.drop(columns = ['BIN_NUM'])
|
|
500
|
+
group_data = group_data.reset_index(drop = True)
|
|
501
|
+
group_data['BIN_NUM'] = (group_data.index + 1).tolist()
|
|
502
|
+
reset_bin_num_res.append(group_data)
|
|
503
|
+
reset_bin_num_res = pd.concat(reset_bin_num_res)
|
|
504
|
+
reset_bin_num_res = reset_bin_num_res[['BIN_RANGE', 'VAR', 'BIN_NUM'] + [x for x in reset_bin_num_res.columns if x not in ['BIN_RANGE', 'VAR', 'BIN_NUM']]]
|
|
505
|
+
|
|
506
|
+
return reset_bin_num_res
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def get_bivar_graph(data, varlist, sep, ref_woe_table, save_dir, group=None, woe_suffix="_woe"):
|
|
510
|
+
"""
|
|
511
|
+
生成双变量分析图表,包括参考WOE图和分组WOE图。
|
|
512
|
+
|
|
513
|
+
Parameters
|
|
514
|
+
----------
|
|
515
|
+
data : pandas.DataFrame
|
|
516
|
+
输入数据,包含原始变量值和分组信息
|
|
517
|
+
varlist : list
|
|
518
|
+
要分析的变量列表
|
|
519
|
+
sep : str
|
|
520
|
+
目标变量名称,用于计算好坏样本比例
|
|
521
|
+
ref_woe_table : pandas.DataFrame
|
|
522
|
+
参考WOE映射表,包含各变量的标准WOE分箱信息
|
|
523
|
+
save_dir : str
|
|
524
|
+
图片保存目录路径
|
|
525
|
+
group : str, optional
|
|
526
|
+
分组字段名称,用于生成分组对比图,默认为None
|
|
527
|
+
woe_suffix : str, optional
|
|
528
|
+
WOE变量后缀,默认为'_woe'
|
|
529
|
+
|
|
530
|
+
Returns
|
|
531
|
+
-------
|
|
532
|
+
None
|
|
533
|
+
函数直接保存图表到指定目录
|
|
534
|
+
|
|
535
|
+
Examples
|
|
536
|
+
--------
|
|
537
|
+
>>> get_bivar_graph(data, ['age', 'income'], 'default', ref_table, './output', group='city')
|
|
538
|
+
"""
|
|
539
|
+
|
|
540
|
+
# try:
|
|
541
|
+
# shutil.rmtree(save_dir)
|
|
542
|
+
# except Exception as e:
|
|
543
|
+
# mkdir_if_not_exist(save_dir)
|
|
544
|
+
|
|
545
|
+
################ Reference WOE Table Plot ##########################
|
|
546
|
+
for var in varlist:
|
|
547
|
+
var = var.replace(woe_suffix, "")
|
|
548
|
+
woe_df = ref_woe_table[ref_woe_table['VAR'] == var]
|
|
549
|
+
plot_woe(woe_df, to_show=False, save_dir=save_dir, fig_name = f"{var}.png")
|
|
550
|
+
|
|
551
|
+
################ Group WOE Table Plot ##########################
|
|
552
|
+
grp_woe_res = get_mapped_woe_summary(data = data,
|
|
553
|
+
ref_woe_table = ref_woe_table,
|
|
554
|
+
tgt_name = sep,
|
|
555
|
+
varlist = varlist,
|
|
556
|
+
grp_name=[group])
|
|
557
|
+
|
|
558
|
+
grp_woe_res = align_bin_num(woe_table = ref_woe_table, grp_woe_df = grp_woe_res, grp_name = [group])
|
|
559
|
+
|
|
560
|
+
if group:
|
|
561
|
+
|
|
562
|
+
for var in varlist:
|
|
563
|
+
var = var.replace(woe_suffix, "")
|
|
564
|
+
woe_grp_df = grp_woe_res[grp_woe_res['VAR'] == var]
|
|
565
|
+
plot_woe_group(woe_grp_df, grp_name = group, to_show=False, save_dir=save_dir, fig_name = f"{var}_{group}.png")
|
|
566
|
+
|
|
567
|
+
return None
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
# =============================================================================
|
|
571
|
+
# 新增类封装
|
|
572
|
+
# =============================================================================
|
|
573
|
+
|
|
574
|
+
class WOEPlotter:
|
|
575
|
+
"""
|
|
576
|
+
WOE绘图类,封装单个变量和分组变量的WOE图表绘制功能。
|
|
577
|
+
|
|
578
|
+
Parameters
|
|
579
|
+
----------
|
|
580
|
+
var_rename : str, optional
|
|
581
|
+
变量重命名,用于图表标题显示,默认为None
|
|
582
|
+
to_show : bool, optional
|
|
583
|
+
是否展示图片,默认为True
|
|
584
|
+
save_dir : str, optional
|
|
585
|
+
结果图片存放的文件夹路径,默认为None
|
|
586
|
+
fig_name : str, optional
|
|
587
|
+
保存图片的文件名,默认为'var.png'
|
|
588
|
+
grp_name : str, optional
|
|
589
|
+
分组字段名称,默认为None
|
|
590
|
+
|
|
591
|
+
Attributes
|
|
592
|
+
----------
|
|
593
|
+
var_rename : str
|
|
594
|
+
变量重命名
|
|
595
|
+
to_show : bool
|
|
596
|
+
是否展示图片
|
|
597
|
+
save_dir : str
|
|
598
|
+
图片保存目录
|
|
599
|
+
fig_name : str
|
|
600
|
+
图片文件名
|
|
601
|
+
grp_name : str
|
|
602
|
+
分组字段名称
|
|
603
|
+
|
|
604
|
+
Examples
|
|
605
|
+
--------
|
|
606
|
+
>>> plotter = WOEPlotter(save_dir='./output', var_rename='年龄')
|
|
607
|
+
>>> plotter.plot(woe_df)
|
|
608
|
+
>>> plotter.plot_group(woe_grp_df, grp_name='城市')
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
def __init__(self, var_rename=None, to_show=True, save_dir=None, fig_name='var.png', grp_name=None):
|
|
612
|
+
"""
|
|
613
|
+
初始化WOEPlotter实例。
|
|
614
|
+
|
|
615
|
+
Parameters
|
|
616
|
+
----------
|
|
617
|
+
var_rename : str, optional
|
|
618
|
+
变量重命名,用于图表标题显示
|
|
619
|
+
to_show : bool, optional
|
|
620
|
+
是否展示图片,默认为True
|
|
621
|
+
save_dir : str, optional
|
|
622
|
+
结果图片存放的文件夹路径
|
|
623
|
+
fig_name : str, optional
|
|
624
|
+
保存图片的文件名,默认为'var.png'
|
|
625
|
+
grp_name : str, optional
|
|
626
|
+
分组字段名称
|
|
627
|
+
"""
|
|
628
|
+
self.var_rename = var_rename
|
|
629
|
+
self.to_show = to_show
|
|
630
|
+
self.save_dir = save_dir
|
|
631
|
+
self.fig_name = fig_name
|
|
632
|
+
self.grp_name = grp_name
|
|
633
|
+
|
|
634
|
+
def plot(self, woe_df, var_rename=None, to_show=None, save_dir=None, fig_name=None):
|
|
635
|
+
"""
|
|
636
|
+
绘制单个变量的WOE图。
|
|
637
|
+
|
|
638
|
+
Parameters
|
|
639
|
+
----------
|
|
640
|
+
woe_df : pandas.DataFrame
|
|
641
|
+
WOE表,包含变量、分箱等信息
|
|
642
|
+
var_rename : str, optional
|
|
643
|
+
变量重命名,会覆盖实例属性
|
|
644
|
+
to_show : bool, optional
|
|
645
|
+
是否展示图片,会覆盖实例属性
|
|
646
|
+
save_dir : str, optional
|
|
647
|
+
图片保存目录,会覆盖实例属性
|
|
648
|
+
fig_name : str, optional
|
|
649
|
+
图片文件名,会覆盖实例属性
|
|
650
|
+
|
|
651
|
+
Returns
|
|
652
|
+
-------
|
|
653
|
+
None
|
|
654
|
+
|
|
655
|
+
Examples
|
|
656
|
+
--------
|
|
657
|
+
>>> plotter = WOEPlotter(save_dir='./output')
|
|
658
|
+
>>> plotter.plot(woe_df, var_rename='年龄')
|
|
659
|
+
"""
|
|
660
|
+
# 使用实例属性作为默认值,允许覆盖
|
|
661
|
+
_var_rename = var_rename if var_rename is not None else self.var_rename
|
|
662
|
+
_to_show = to_show if to_show is not None else self.to_show
|
|
663
|
+
_save_dir = save_dir if save_dir is not None else self.save_dir
|
|
664
|
+
_fig_name = fig_name if fig_name is not None else self.fig_name
|
|
665
|
+
|
|
666
|
+
plot_woe(woe_df, _var_rename, _to_show, _save_dir, _fig_name)
|
|
667
|
+
|
|
668
|
+
def plot_group(self, woe_grp_df, grp_name=None, var_rename=None, to_show=None, save_dir=None, fig_name=None):
|
|
669
|
+
"""
|
|
670
|
+
绘制分组变量的WOE图。
|
|
671
|
+
|
|
672
|
+
Parameters
|
|
673
|
+
----------
|
|
674
|
+
woe_grp_df : pandas.DataFrame
|
|
675
|
+
分组WOE表,包含按组别分组后的WOE信息
|
|
676
|
+
grp_name : str, optional
|
|
677
|
+
分组字段名称,会覆盖实例属性
|
|
678
|
+
var_rename : str, optional
|
|
679
|
+
变量重命名,会覆盖实例属性
|
|
680
|
+
to_show : bool, optional
|
|
681
|
+
是否展示图片,会覆盖实例属性
|
|
682
|
+
save_dir : str, optional
|
|
683
|
+
图片保存目录,会覆盖实例属性
|
|
684
|
+
fig_name : str, optional
|
|
685
|
+
图片文件名,会覆盖实例属性
|
|
686
|
+
|
|
687
|
+
Returns
|
|
688
|
+
-------
|
|
689
|
+
None
|
|
690
|
+
|
|
691
|
+
Examples
|
|
692
|
+
--------
|
|
693
|
+
>>> plotter = WOEPlotter(save_dir='./output')
|
|
694
|
+
>>> plotter.plot_group(woe_grp_df, grp_name='城市')
|
|
695
|
+
"""
|
|
696
|
+
_grp_name = grp_name if grp_name is not None else self.grp_name
|
|
697
|
+
_var_rename = var_rename if var_rename is not None else self.var_rename
|
|
698
|
+
_to_show = to_show if to_show is not None else self.to_show
|
|
699
|
+
_save_dir = save_dir if save_dir is not None else self.save_dir
|
|
700
|
+
_fig_name = fig_name if fig_name is not None else self.fig_name
|
|
701
|
+
|
|
702
|
+
plot_woe_group(woe_grp_df, _grp_name, _var_rename, _to_show, _save_dir, _fig_name)
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
class WOEAnalyzer:
|
|
706
|
+
"""
|
|
707
|
+
WOE分析器类,封装WOE表计算和映射汇总功能。
|
|
708
|
+
|
|
709
|
+
Parameters
|
|
710
|
+
----------
|
|
711
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
712
|
+
参考WOE映射表,包含各变量的标准WOE分箱信息,默认为None
|
|
713
|
+
tgt_name : str, optional
|
|
714
|
+
目标变量名称,用于计算好坏样本比例,默认为None
|
|
715
|
+
|
|
716
|
+
Attributes
|
|
717
|
+
----------
|
|
718
|
+
ref_woe_table : pandas.DataFrame
|
|
719
|
+
参考WOE映射表
|
|
720
|
+
tgt_name : str
|
|
721
|
+
目标变量名称
|
|
722
|
+
|
|
723
|
+
Examples
|
|
724
|
+
--------
|
|
725
|
+
>>> analyzer = WOEAnalyzer(ref_woe_table, tgt_name='default')
|
|
726
|
+
>>> woe_table, woe_dict = analyzer.get_woe_table(binning_res, 'age')
|
|
727
|
+
>>> summary = analyzer.get_summary(data, 'income')
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
def __init__(self, ref_woe_table=None, tgt_name=None):
|
|
731
|
+
"""
|
|
732
|
+
初始化WOEAnalyzer实例。
|
|
733
|
+
|
|
734
|
+
Parameters
|
|
735
|
+
----------
|
|
736
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
737
|
+
参考WOE映射表
|
|
738
|
+
tgt_name : str, optional
|
|
739
|
+
目标变量名称
|
|
740
|
+
"""
|
|
741
|
+
self.ref_woe_table = ref_woe_table
|
|
742
|
+
self.tgt_name = tgt_name
|
|
743
|
+
|
|
744
|
+
def get_woe_table(self, binning_res, var, dep=None):
|
|
745
|
+
"""
|
|
746
|
+
根据分箱结果计算并返回WOE表和WOE映射字典。
|
|
747
|
+
|
|
748
|
+
Parameters
|
|
749
|
+
----------
|
|
750
|
+
binning_res : pandas.DataFrame
|
|
751
|
+
包含分箱结果的数据框
|
|
752
|
+
var : str
|
|
753
|
+
变量名称
|
|
754
|
+
dep : str, optional
|
|
755
|
+
目标变量名称,会覆盖实例属性tgt_name
|
|
756
|
+
|
|
757
|
+
Returns
|
|
758
|
+
-------
|
|
759
|
+
tuple
|
|
760
|
+
- woe_table (pandas.DataFrame): WOE表
|
|
761
|
+
- woe_mapping_dict (dict): WOE映射字典
|
|
762
|
+
|
|
763
|
+
Examples
|
|
764
|
+
--------
|
|
765
|
+
>>> analyzer = WOEAnalyzer(tgt_name='default')
|
|
766
|
+
>>> woe_table, woe_dict = analyzer.get_woe_table(binning_res, 'age')
|
|
767
|
+
"""
|
|
768
|
+
_dep = dep if dep is not None else self.tgt_name
|
|
769
|
+
return get_woe_table(binning_res, var, _dep)
|
|
770
|
+
|
|
771
|
+
def get_mapped_woe_summary_single(self, data, var, ref_woe_table=None, tgt_name=None):
|
|
772
|
+
"""
|
|
773
|
+
根据参考WOE映射表对单个变量生成WOE汇总表。
|
|
774
|
+
|
|
775
|
+
Parameters
|
|
776
|
+
----------
|
|
777
|
+
data : pandas.DataFrame
|
|
778
|
+
输入数据
|
|
779
|
+
var : str
|
|
780
|
+
变量名称
|
|
781
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
782
|
+
参考WOE表,会覆盖实例属性
|
|
783
|
+
tgt_name : str, optional
|
|
784
|
+
目标变量名称,会覆盖实例属性
|
|
785
|
+
|
|
786
|
+
Returns
|
|
787
|
+
-------
|
|
788
|
+
pandas.DataFrame
|
|
789
|
+
变量WOE汇总表
|
|
790
|
+
|
|
791
|
+
Examples
|
|
792
|
+
--------
|
|
793
|
+
>>> analyzer = WOEAnalyzer(ref_woe_table, 'default')
|
|
794
|
+
>>> summary = analyzer.get_mapped_woe_summary_single(data, 'income')
|
|
795
|
+
"""
|
|
796
|
+
_ref_woe_table = ref_woe_table if ref_woe_table is not None else self.ref_woe_table
|
|
797
|
+
_tgt_name = tgt_name if tgt_name is not None else self.tgt_name
|
|
798
|
+
return get_mapped_woe_summary_single(data, var, _ref_woe_table, _tgt_name)
|
|
799
|
+
|
|
800
|
+
def get_mapped_woe_summary_grp(self, data, var, ref_woe_table=None, tgt_name=None, grp_name=None):
|
|
801
|
+
"""
|
|
802
|
+
获取分组后的单个变量WOE汇总表。
|
|
803
|
+
|
|
804
|
+
Parameters
|
|
805
|
+
----------
|
|
806
|
+
data : pandas.DataFrame
|
|
807
|
+
输入数据
|
|
808
|
+
var : str
|
|
809
|
+
变量名称
|
|
810
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
811
|
+
参考WOE表,会覆盖实例属性
|
|
812
|
+
tgt_name : str, optional
|
|
813
|
+
目标变量名称,会覆盖实例属性
|
|
814
|
+
grp_name : str or list, optional
|
|
815
|
+
分组字段名称
|
|
816
|
+
|
|
817
|
+
Returns
|
|
818
|
+
-------
|
|
819
|
+
pandas.DataFrame
|
|
820
|
+
分组后的变量WOE汇总表
|
|
821
|
+
|
|
822
|
+
Examples
|
|
823
|
+
--------
|
|
824
|
+
>>> analyzer = WOEAnalyzer(ref_woe_table, 'default')
|
|
825
|
+
>>> summary = analyzer.get_mapped_woe_summary_grp(data, 'age', grp_name='city')
|
|
826
|
+
"""
|
|
827
|
+
_ref_woe_table = ref_woe_table if ref_woe_table is not None else self.ref_woe_table
|
|
828
|
+
_tgt_name = tgt_name if tgt_name is not None else self.tgt_name
|
|
829
|
+
return get_mapped_woe_summary_grp(data, var, _ref_woe_table, _tgt_name, grp_name)
|
|
830
|
+
|
|
831
|
+
def get_mapped_woe_summary(self, data, ref_woe_table=None, tgt_name=None, varlist=None, grp_name=None):
|
|
832
|
+
"""
|
|
833
|
+
获取多个变量的WOE汇总表。
|
|
834
|
+
|
|
835
|
+
Parameters
|
|
836
|
+
----------
|
|
837
|
+
data : pandas.DataFrame
|
|
838
|
+
输入数据
|
|
839
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
840
|
+
参考WOE表,会覆盖实例属性
|
|
841
|
+
tgt_name : str, optional
|
|
842
|
+
目标变量名称,会覆盖实例属性
|
|
843
|
+
varlist : list, optional
|
|
844
|
+
要计算的变量列表
|
|
845
|
+
grp_name : str or list, optional
|
|
846
|
+
分组字段名称
|
|
847
|
+
|
|
848
|
+
Returns
|
|
849
|
+
-------
|
|
850
|
+
pandas.DataFrame
|
|
851
|
+
包含所有变量WOE信息的汇总表
|
|
852
|
+
|
|
853
|
+
Examples
|
|
854
|
+
--------
|
|
855
|
+
>>> analyzer = WOEAnalyzer(ref_woe_table, 'default')
|
|
856
|
+
>>> summary = analyzer.get_mapped_woe_summary(data, varlist=['age', 'income'])
|
|
857
|
+
"""
|
|
858
|
+
_ref_woe_table = ref_woe_table if ref_woe_table is not None else self.ref_woe_table
|
|
859
|
+
_tgt_name = tgt_name if tgt_name is not None else self.tgt_name
|
|
860
|
+
return get_mapped_woe_summary(data, _ref_woe_table, _tgt_name, varlist, grp_name)
|
|
861
|
+
|
|
862
|
+
def align_bin_num(self, woe_table, grp_woe_df, grp_name):
|
|
863
|
+
"""
|
|
864
|
+
对齐分组WOE表与参考WOE表的分箱编号。
|
|
865
|
+
|
|
866
|
+
Parameters
|
|
867
|
+
----------
|
|
868
|
+
woe_table : pandas.DataFrame
|
|
869
|
+
参考WOE表
|
|
870
|
+
grp_woe_df : pandas.DataFrame
|
|
871
|
+
分组WOE表
|
|
872
|
+
grp_name : str or list
|
|
873
|
+
分组字段名称
|
|
874
|
+
|
|
875
|
+
Returns
|
|
876
|
+
-------
|
|
877
|
+
pandas.DataFrame
|
|
878
|
+
对齐后的分组WOE表
|
|
879
|
+
|
|
880
|
+
Examples
|
|
881
|
+
--------
|
|
882
|
+
>>> analyzer = WOEAnalyzer()
|
|
883
|
+
>>> aligned = analyzer.align_bin_num(ref_table, grp_df, 'city')
|
|
884
|
+
"""
|
|
885
|
+
return align_bin_num(woe_table, grp_woe_df, grp_name)
|
|
886
|
+
|
|
887
|
+
def get_bivar_graph(self, data, varlist, sep=None, ref_woe_table=None, save_dir=None, group=None, woe_suffix="_woe"):
|
|
888
|
+
"""
|
|
889
|
+
生成双变量分析图表。
|
|
890
|
+
|
|
891
|
+
Parameters
|
|
892
|
+
----------
|
|
893
|
+
data : pandas.DataFrame
|
|
894
|
+
输入数据
|
|
895
|
+
varlist : list
|
|
896
|
+
要分析的变量列表
|
|
897
|
+
sep : str, optional
|
|
898
|
+
目标变量名称,会覆盖实例属性tgt_name
|
|
899
|
+
ref_woe_table : pandas.DataFrame, optional
|
|
900
|
+
参考WOE表,会覆盖实例属性
|
|
901
|
+
save_dir : str, optional
|
|
902
|
+
图片保存目录
|
|
903
|
+
group : str, optional
|
|
904
|
+
分组字段名称
|
|
905
|
+
woe_suffix : str, optional
|
|
906
|
+
WOE变量后缀,默认为'_woe'
|
|
907
|
+
|
|
908
|
+
Returns
|
|
909
|
+
-------
|
|
910
|
+
None
|
|
911
|
+
|
|
912
|
+
Examples
|
|
913
|
+
--------
|
|
914
|
+
>>> analyzer = WOEAnalyzer(ref_woe_table, 'default')
|
|
915
|
+
>>> analyzer.get_bivar_graph(data, ['age', 'income'], save_dir='./output', group='city')
|
|
916
|
+
"""
|
|
917
|
+
_sep = sep if sep is not None else self.tgt_name
|
|
918
|
+
_ref_woe_table = ref_woe_table if ref_woe_table is not None else self.ref_woe_table
|
|
919
|
+
return get_bivar_graph(data, varlist, _sep, _ref_woe_table, save_dir, group, woe_suffix)
|