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,762 @@
|
|
|
1
|
+
"""
|
|
2
|
+
变量提取与相关性分析工具包
|
|
3
|
+
提供变量分析、IV计算、WOE绑图和相关性过滤功能
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
from .Distribution_Tool import proc_means_by_grp
|
|
10
|
+
import logging
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class VarExtractionInsights:
|
|
14
|
+
"""变量提取与洞察分析器。
|
|
15
|
+
用于对数据集进行变量分析,计算IV值、WOE分箱,
|
|
16
|
+
并支持可视化绑图和变量筛选。
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
data : pd.DataFrame
|
|
21
|
+
输入的原始数据框
|
|
22
|
+
dep : str
|
|
23
|
+
目标变量(因变量)列名
|
|
24
|
+
plot_path : str
|
|
25
|
+
绑图保存路径
|
|
26
|
+
nbins : int, optional
|
|
27
|
+
分箱数量,默认为10
|
|
28
|
+
equal_freq : bool, optional
|
|
29
|
+
是否使用等频分箱,默认为True
|
|
30
|
+
min_bin_prop : float, optional
|
|
31
|
+
每个分箱的最小样本比例,默认为0.05
|
|
32
|
+
precision : int, optional
|
|
33
|
+
WOE和IV计算精度,默认为5
|
|
34
|
+
chi2_method : bool, optional
|
|
35
|
+
是否使用卡方分箱方法,默认为False
|
|
36
|
+
chi2_p : float, optional
|
|
37
|
+
卡方检验的p值阈值,默认为0.9
|
|
38
|
+
init_equi_bins : int, optional
|
|
39
|
+
初始等频分箱数量,默认为5000
|
|
40
|
+
tree_binning : bool, optional
|
|
41
|
+
是否使用决策树分箱,默认为True
|
|
42
|
+
include_missing : bool, optional
|
|
43
|
+
是否将缺失值作为单独分箱,默认为True
|
|
44
|
+
seed : int, optional
|
|
45
|
+
随机种子,默认为3407
|
|
46
|
+
missing_rate_ref : int/float, optional
|
|
47
|
+
缺失值填充参考值,默认为-999999
|
|
48
|
+
spec_values : list, optional
|
|
49
|
+
特殊值列表,默认为空列表
|
|
50
|
+
|
|
51
|
+
Examples
|
|
52
|
+
--------
|
|
53
|
+
>>> analyzer = VarExtractionInsights(df, 'target', '/path/to/plots')
|
|
54
|
+
>>> report = analyzer.get_var_analysis_report(df, ['var1', 'var2'])
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, data, dep, plot_path,
|
|
58
|
+
nbins=10, equal_freq=True, min_bin_prop=0.05, precision=5, chi2_method=False, chi2_p=0.9,
|
|
59
|
+
init_equi_bins=5000, tree_binning=True, include_missing=True, seed=3407, missing_rate_ref=-999999, spec_values=None):
|
|
60
|
+
"""初始化变量提取与洞察分析器。
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
data : pd.DataFrame
|
|
65
|
+
输入的原始数据框
|
|
66
|
+
dep : str
|
|
67
|
+
目标变量(因变量)列名
|
|
68
|
+
plot_path : str
|
|
69
|
+
绑图保存路径
|
|
70
|
+
nbins : int, optional
|
|
71
|
+
分箱数量
|
|
72
|
+
equal_freq : bool, optional
|
|
73
|
+
是否使用等频分箱
|
|
74
|
+
min_bin_prop : float, optional
|
|
75
|
+
每个分箱的最小样本比例
|
|
76
|
+
precision : int, optional
|
|
77
|
+
WOE和IV计算精度
|
|
78
|
+
chi2_method : bool, optional
|
|
79
|
+
是否使用卡方分箱方法
|
|
80
|
+
chi2_p : float, optional
|
|
81
|
+
卡方检验的p值阈值
|
|
82
|
+
init_equi_bins : int, optional
|
|
83
|
+
初始等频分箱数量
|
|
84
|
+
tree_binning : bool, optional
|
|
85
|
+
是否使用决策树分箱
|
|
86
|
+
include_missing : bool, optional
|
|
87
|
+
是否将缺失值作为单独分箱
|
|
88
|
+
seed : int, optional
|
|
89
|
+
随机种子
|
|
90
|
+
missing_rate_ref : int/float, optional
|
|
91
|
+
缺失值填充参考值
|
|
92
|
+
spec_values : list, optional
|
|
93
|
+
特殊值列表
|
|
94
|
+
"""
|
|
95
|
+
self.data = data
|
|
96
|
+
self.dep = dep
|
|
97
|
+
self.plot_path = plot_path
|
|
98
|
+
|
|
99
|
+
self.nbins = nbins
|
|
100
|
+
self.equal_freq = equal_freq
|
|
101
|
+
self.min_bin_prop = min_bin_prop
|
|
102
|
+
self.precision = precision
|
|
103
|
+
self.chi2_method = chi2_method
|
|
104
|
+
self.chi2_p = chi2_p
|
|
105
|
+
self.init_equi_bins = init_equi_bins
|
|
106
|
+
self.tree_binning = tree_binning
|
|
107
|
+
self.include_missing = include_missing
|
|
108
|
+
self.seed = seed
|
|
109
|
+
self.missing_rate_ref = missing_rate_ref
|
|
110
|
+
self.spec_values = spec_values if spec_values is not None else []
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def remove_folder(file_path):
|
|
114
|
+
"""删除指定文件夹。
|
|
115
|
+
|
|
116
|
+
递归删除指定路径的文件夹及其所有内容,
|
|
117
|
+
如果文件夹不存在则静默处理。
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
file_path : str
|
|
122
|
+
要删除的文件夹路径
|
|
123
|
+
|
|
124
|
+
Examples
|
|
125
|
+
--------
|
|
126
|
+
>>> VarExtractionInsights.remove_folder('/path/to/folder')
|
|
127
|
+
"""
|
|
128
|
+
import shutil
|
|
129
|
+
try:
|
|
130
|
+
shutil.rmtree(file_path)
|
|
131
|
+
except Exception:
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
def get_var_analysis_report(self, data, varlist, dep=None, iv_cut=0.01):
|
|
135
|
+
"""生成变量分析报告。
|
|
136
|
+
|
|
137
|
+
对指定变量列表计算IV值、KS值、Lift值等指标,
|
|
138
|
+
并返回满足IV阈值的变量分析汇总结果。
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
data : pd.DataFrame
|
|
143
|
+
输入的原始数据框
|
|
144
|
+
varlist : list
|
|
145
|
+
待分析的变量名列表
|
|
146
|
+
dep : str, optional
|
|
147
|
+
目标变量列名,默认为None(使用初始化时的dep)
|
|
148
|
+
iv_cut : float, optional
|
|
149
|
+
IV值筛选阈值,默认为0.01
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
pd.DataFrame
|
|
154
|
+
包含变量分析结果的汇总表,包括:
|
|
155
|
+
- var: 变量名
|
|
156
|
+
- n_all: 总样本数
|
|
157
|
+
- n: 非缺失样本数
|
|
158
|
+
- ks_in_gains: KS统计量
|
|
159
|
+
- lift_in_gains: Lift值
|
|
160
|
+
- iv: IV值
|
|
161
|
+
- n_bump: 分箱数量
|
|
162
|
+
- missing_rate: 缺失率
|
|
163
|
+
- min, mean, max: 统计量
|
|
164
|
+
- n_bins: 分箱数
|
|
165
|
+
|
|
166
|
+
Examples
|
|
167
|
+
--------
|
|
168
|
+
>>> analyzer = VarExtractionInsights(df, 'target', '/path/to/plots')
|
|
169
|
+
>>> report = analyzer.get_var_analysis_report(df, ['var1', 'var2'])
|
|
170
|
+
"""
|
|
171
|
+
if dep is None:
|
|
172
|
+
dep = self.dep
|
|
173
|
+
|
|
174
|
+
from Modeling_Tool.Eval.Model_Eval_Tool import get_gains_table
|
|
175
|
+
|
|
176
|
+
iv_info_res = []
|
|
177
|
+
for var in tqdm(varlist):
|
|
178
|
+
if data[var].nunique() > 1:
|
|
179
|
+
try:
|
|
180
|
+
attr_iv = get_gains_table(
|
|
181
|
+
data=data,
|
|
182
|
+
dep=self.dep,
|
|
183
|
+
nbins=self.nbins,
|
|
184
|
+
precision=self.precision,
|
|
185
|
+
min_bin_prop=self.min_bin_prop,
|
|
186
|
+
include_missing=self.include_missing,
|
|
187
|
+
score=var,
|
|
188
|
+
equal_freq=self.equal_freq,
|
|
189
|
+
chi2_method=self.chi2_method,
|
|
190
|
+
chi2_p=self.chi2_p,
|
|
191
|
+
init_equi_bins=self.init_equi_bins,
|
|
192
|
+
fillna=self.missing_rate_ref,
|
|
193
|
+
spec_values=self.spec_values,
|
|
194
|
+
retSummary=True,
|
|
195
|
+
tree_binning=self.tree_binning,
|
|
196
|
+
random_state=self.seed,
|
|
197
|
+
ascending=True,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
attr_iv['var'] = var
|
|
201
|
+
iv_info_res.append(attr_iv)
|
|
202
|
+
|
|
203
|
+
except TypeError:
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
iv_info_res = pd.concat(iv_info_res).sort_values("IV", ascending=False)
|
|
207
|
+
|
|
208
|
+
high_iv_summary = iv_info_res.query(f"IV >= {iv_cut}").round(4)
|
|
209
|
+
high_iv_varlist = high_iv_summary['var'].tolist()
|
|
210
|
+
|
|
211
|
+
means = proc_means_by_grp(data, high_iv_varlist, spec_missing_value=self.missing_rate_ref)
|
|
212
|
+
|
|
213
|
+
if len(high_iv_varlist) == 0:
|
|
214
|
+
logger.info(f"WARNING: No variable with IV >= {iv_cut}")
|
|
215
|
+
means = means.rename(columns={"index": "attribute"})
|
|
216
|
+
|
|
217
|
+
fnl_summary = high_iv_summary.merge(
|
|
218
|
+
means[['attribute', 'N_ALL', 'N', 'MISSING_RATE', 'MIN', 'MEAN', 'MAX']],
|
|
219
|
+
left_on=['var'],
|
|
220
|
+
right_on=['attribute'],
|
|
221
|
+
how='left'
|
|
222
|
+
)
|
|
223
|
+
fnl_summary.columns = [x.lower() for x in fnl_summary.columns]
|
|
224
|
+
fnl_summary = fnl_summary[[
|
|
225
|
+
'var', 'n_all', 'n', 'ks_in_gains', 'lift_in_gains', 'iv',
|
|
226
|
+
'n_bump', 'missing_rate', 'min', 'mean', 'max', 'n_bins'
|
|
227
|
+
]]
|
|
228
|
+
|
|
229
|
+
return fnl_summary
|
|
230
|
+
|
|
231
|
+
def plot_woe(self, data, varlist, plot_group=None, plot_dirname="var_analysis_plot", plot_path=None):
|
|
232
|
+
"""绑制WOE分布图。
|
|
233
|
+
|
|
234
|
+
对指定变量列表计算WOE值并绑制分布图,
|
|
235
|
+
保存到指定目录。
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
data : pd.DataFrame
|
|
240
|
+
输入的原始数据框
|
|
241
|
+
varlist : list
|
|
242
|
+
待绑图的变量名列表
|
|
243
|
+
plot_group : str, optional
|
|
244
|
+
分组变量名,默认为None
|
|
245
|
+
plot_dirname : str, optional
|
|
246
|
+
绑图保存子目录名,默认为"var_analysis_plot"
|
|
247
|
+
plot_path : str, optional
|
|
248
|
+
绑图保存根路径,默认为None(使用初始化时的plot_path)
|
|
249
|
+
|
|
250
|
+
Returns
|
|
251
|
+
-------
|
|
252
|
+
None
|
|
253
|
+
|
|
254
|
+
Examples
|
|
255
|
+
--------
|
|
256
|
+
>>> analyzer = VarExtractionInsights(df, 'target', '/path/to/plots')
|
|
257
|
+
>>> analyzer.plot_woe(df, ['var1', 'var2'])
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
if plot_path is None:
|
|
261
|
+
plot_path = self.plot_path
|
|
262
|
+
|
|
263
|
+
from Modeling_Tool.WOE.WOE_Master import WOE_Master
|
|
264
|
+
|
|
265
|
+
# Fill Missing Value.
|
|
266
|
+
drv_fillna = data.copy()
|
|
267
|
+
drv_fillna[varlist] = drv_fillna[varlist].fillna(self.missing_rate_ref)
|
|
268
|
+
|
|
269
|
+
woe_master = WOE_Master(
|
|
270
|
+
train_data=drv_fillna,
|
|
271
|
+
varlist=varlist,
|
|
272
|
+
dep=self.dep,
|
|
273
|
+
graph_save_dir=plot_path
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
woe_master.fit(
|
|
277
|
+
nbins=self.nbins,
|
|
278
|
+
equal_freq=self.equal_freq,
|
|
279
|
+
min_bin_prop=self.min_bin_prop,
|
|
280
|
+
precision=self.precision,
|
|
281
|
+
chi2_config=(self.init_equi_bins, self.chi2_p) if self.chi2_method else None,
|
|
282
|
+
tree_binning_seed=self.seed if self.tree_binning else None,
|
|
283
|
+
include_missing=self.include_missing,
|
|
284
|
+
spec_values=self.spec_values
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
train_woe = woe_master.transform(drv_fillna)
|
|
288
|
+
woe_master.plot_bivar_graph(train_woe, group=plot_group, dirname=plot_dirname)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def var_corr_filter(data, varlist, corr_cutpoint=0.8, method='pearson'):
|
|
294
|
+
"""筛选高相关变量对。
|
|
295
|
+
|
|
296
|
+
计算变量间的相关系数,返回超过阈值的高相关变量对列表。
|
|
297
|
+
|
|
298
|
+
Parameters
|
|
299
|
+
----------
|
|
300
|
+
data : pd.DataFrame
|
|
301
|
+
输入的数据框
|
|
302
|
+
varlist : list
|
|
303
|
+
待筛选的变量名列表
|
|
304
|
+
corr_cutpoint : float, optional
|
|
305
|
+
相关系数阈值,默认为0.8
|
|
306
|
+
method : str, optional
|
|
307
|
+
相关系数计算方法,可选'pearson'、'spearman'、'kendall',
|
|
308
|
+
默认为'pearson'
|
|
309
|
+
|
|
310
|
+
Returns
|
|
311
|
+
-------
|
|
312
|
+
pd.DataFrame
|
|
313
|
+
包含高相关变量对的数据框,包括:
|
|
314
|
+
- VAR1: 变量1
|
|
315
|
+
- VAR2: 变量2
|
|
316
|
+
- CORR: 相关系数
|
|
317
|
+
|
|
318
|
+
Examples
|
|
319
|
+
--------
|
|
320
|
+
>>> high_corr = var_corr_filter(df, ['var1', 'var2', 'var3'], corr_cutpoint=0.8)
|
|
321
|
+
"""
|
|
322
|
+
import numpy as np
|
|
323
|
+
|
|
324
|
+
corr_matrix = data[varlist].corr(method=method)
|
|
325
|
+
|
|
326
|
+
corr_list = []
|
|
327
|
+
for i in range(len(varlist)):
|
|
328
|
+
for j in range(i + 1, len(varlist)):
|
|
329
|
+
var1, var2 = varlist[i], varlist[j]
|
|
330
|
+
corr_value = corr_matrix.iloc[i, j]
|
|
331
|
+
if abs(corr_value) > corr_cutpoint:
|
|
332
|
+
corr_list.append({
|
|
333
|
+
'VAR1': var1,
|
|
334
|
+
'VAR2': var2,
|
|
335
|
+
'CORR': corr_value
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
return pd.DataFrame(corr_list)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class CorrelationFilter:
|
|
343
|
+
"""相关性过滤分析器。
|
|
344
|
+
|
|
345
|
+
提供基于相关性分析的高相关变量筛选和去除功能,
|
|
346
|
+
支持IV值对比和迭代筛选。
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
data : pd.DataFrame
|
|
351
|
+
输入的原始数据框
|
|
352
|
+
dep : str
|
|
353
|
+
目标变量(因变量)列名
|
|
354
|
+
corr_cutpoint : float, optional
|
|
355
|
+
相关系数阈值,超过该值的变量对将被筛选,默认为0.8
|
|
356
|
+
method : str, optional
|
|
357
|
+
相关系数计算方法,可选'pearson'、'spearman'、'kendall',默认为'pearson'
|
|
358
|
+
|
|
359
|
+
Examples
|
|
360
|
+
--------
|
|
361
|
+
>>> filter_analyzer = CorrelationFilter(df, 'target')
|
|
362
|
+
>>> keep_vars = filter_analyzer.remove_highly_correlated(['var1', 'var2'])
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
def __init__(self, data, dep, corr_cutpoint=0.8, method='pearson', tree_binning=False, chi2_method=False, seed = 42, chi2_p =0.999, init_equi_bins = 1000,
|
|
366
|
+
missing_rate_ref = -9999999, spec_values = [], base_metric = 'iv'):
|
|
367
|
+
"""初始化相关性过滤分析器。
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
data : pd.DataFrame
|
|
372
|
+
输入的原始数据框
|
|
373
|
+
dep : str
|
|
374
|
+
目标变量(因变量)列名
|
|
375
|
+
corr_cutpoint : float, optional
|
|
376
|
+
相关系数阈值
|
|
377
|
+
method : str, optional
|
|
378
|
+
相关系数计算方法
|
|
379
|
+
tree_binning_seed : int, optional
|
|
380
|
+
决策树分箱随机种子
|
|
381
|
+
chi2_config : tuple, optional
|
|
382
|
+
卡方分箱配置
|
|
383
|
+
"""
|
|
384
|
+
self.data = data
|
|
385
|
+
self.dep = dep
|
|
386
|
+
self.corr_cutpoint = corr_cutpoint
|
|
387
|
+
self.method = method
|
|
388
|
+
self.tree_binning = tree_binning
|
|
389
|
+
self.chi2_method = chi2_method
|
|
390
|
+
self.seed = seed
|
|
391
|
+
self.chi2_p = chi2_p
|
|
392
|
+
self.init_equi_bins = init_equi_bins
|
|
393
|
+
self.missing_rate_ref = missing_rate_ref
|
|
394
|
+
self.spec_values = spec_values
|
|
395
|
+
self.base_metric = base_metric
|
|
396
|
+
|
|
397
|
+
self.correlated_dict = {}
|
|
398
|
+
self.filtered_varlist = []
|
|
399
|
+
|
|
400
|
+
def filter_single_iteration(self, varlist):
|
|
401
|
+
"""单次迭代过滤高相关变量。
|
|
402
|
+
|
|
403
|
+
对变量列表执行一次相关性过滤,保留IV值最高的变量。
|
|
404
|
+
|
|
405
|
+
Parameters
|
|
406
|
+
----------
|
|
407
|
+
varlist : list
|
|
408
|
+
待筛选的变量名列表
|
|
409
|
+
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
list
|
|
413
|
+
筛选后保留的变量名列表
|
|
414
|
+
"""
|
|
415
|
+
base_metric = self.base_metric.lower()
|
|
416
|
+
|
|
417
|
+
name_mapping = {
|
|
418
|
+
"iv": "iv",
|
|
419
|
+
"ks": "ks_in_gains"
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
high_corr_var = var_corr_filter(
|
|
423
|
+
self.data, varlist,
|
|
424
|
+
corr_cutpoint=self.corr_cutpoint,
|
|
425
|
+
method=self.method
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
if len(high_corr_var) == 0:
|
|
429
|
+
return varlist
|
|
430
|
+
|
|
431
|
+
base_varlist = high_corr_var['VAR1'].drop_duplicates().tolist()
|
|
432
|
+
|
|
433
|
+
correlated_dict = self.correlated_dict
|
|
434
|
+
selected_varlist = []
|
|
435
|
+
removed_varlist = []
|
|
436
|
+
for var in tqdm(base_varlist):
|
|
437
|
+
if var not in set(removed_varlist + selected_varlist):
|
|
438
|
+
single_var_corr = high_corr_var.query(f""" VAR1 == '{var}'""")
|
|
439
|
+
correlated_list = [var] + single_var_corr['VAR2'].drop_duplicates().tolist()
|
|
440
|
+
|
|
441
|
+
varInsights = VarExtractionInsights(data = self.data,
|
|
442
|
+
dep = self.dep,
|
|
443
|
+
plot_path = None,
|
|
444
|
+
nbins = 10,
|
|
445
|
+
equal_freq = True,
|
|
446
|
+
min_bin_prop = 0.05,
|
|
447
|
+
precision = 5,
|
|
448
|
+
chi2_method = self.chi2_method,
|
|
449
|
+
chi2_p = self.chi2_p,
|
|
450
|
+
init_equi_bins = self.init_equi_bins,
|
|
451
|
+
tree_binning = self.tree_binning,
|
|
452
|
+
include_missing = True,
|
|
453
|
+
seed = self.seed,
|
|
454
|
+
missing_rate_ref = self.missing_rate_ref)
|
|
455
|
+
|
|
456
|
+
fnl_summary = varInsights.get_var_analysis_report(data = self.data, varlist = correlated_list, dep = self.dep, iv_cut = 0)
|
|
457
|
+
fnl_selected_var = fnl_summary.sort_values([name_mapping[base_metric]], ascending = False)['var'][0]
|
|
458
|
+
|
|
459
|
+
if fnl_selected_var not in selected_varlist:
|
|
460
|
+
selected_varlist.append(fnl_selected_var)
|
|
461
|
+
|
|
462
|
+
removed_varlist += [x for x in correlated_list if x != fnl_selected_var and x not in removed_varlist]
|
|
463
|
+
|
|
464
|
+
if var not in correlated_dict:
|
|
465
|
+
correlated_dict[var] = {}
|
|
466
|
+
correlated_dict[var]['corr'] = single_var_corr
|
|
467
|
+
correlated_dict[var]['gains'] = fnl_summary
|
|
468
|
+
else:
|
|
469
|
+
correlated_dict[var]['corr'] = pd.concat([correlated_dict[var]['corr'], single_var_corr]).drop_duplicates()
|
|
470
|
+
correlated_dict[var]['gains'] = pd.concat([correlated_dict[var]['gains'], fnl_summary]).drop_duplicates()
|
|
471
|
+
|
|
472
|
+
other_varlist = [x for x in varlist if x not in (selected_varlist + removed_varlist)]
|
|
473
|
+
fnl_keep_varlist = selected_varlist + other_varlist
|
|
474
|
+
|
|
475
|
+
self.correlated_dict = correlated_dict
|
|
476
|
+
|
|
477
|
+
return fnl_keep_varlist
|
|
478
|
+
|
|
479
|
+
def remove_highly_correlated(self, varlist, max_iterations=10):
|
|
480
|
+
"""迭代去除高相关变量。
|
|
481
|
+
|
|
482
|
+
反复执行相关性过滤,直到没有变量被移除或达到最大迭代次数。
|
|
483
|
+
|
|
484
|
+
Parameters
|
|
485
|
+
----------
|
|
486
|
+
varlist : list
|
|
487
|
+
待筛选的变量名列表
|
|
488
|
+
max_iterations : int, optional
|
|
489
|
+
最大迭代次数,默认为10
|
|
490
|
+
|
|
491
|
+
Returns
|
|
492
|
+
-------
|
|
493
|
+
list
|
|
494
|
+
最终保留的变量名列表
|
|
495
|
+
|
|
496
|
+
Examples
|
|
497
|
+
--------
|
|
498
|
+
>>> filter_analyzer = CorrelationFilter(df, 'target')
|
|
499
|
+
>>> keep_vars = filter_analyzer.remove_highly_correlated(['var1', 'var2', 'var3'])
|
|
500
|
+
"""
|
|
501
|
+
last_keep_list = self.filter_single_iteration(varlist)
|
|
502
|
+
|
|
503
|
+
for i in range(1, max_iterations):
|
|
504
|
+
fnl_keep_list = self.filter_single_iteration(last_keep_list)
|
|
505
|
+
|
|
506
|
+
removed_vars = [x for x in last_keep_list if x not in fnl_keep_list]
|
|
507
|
+
self.filtered_varlist.append(removed_vars)
|
|
508
|
+
if len(removed_vars) == 0:
|
|
509
|
+
break
|
|
510
|
+
|
|
511
|
+
last_keep_list = fnl_keep_list
|
|
512
|
+
|
|
513
|
+
self.filtered_varlist = [x for x in varlist if x not in last_keep_list]
|
|
514
|
+
return last_keep_list
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
@staticmethod
|
|
518
|
+
def calculate_vif(df):
|
|
519
|
+
"""计算方差膨胀因子(VIF)。
|
|
520
|
+
|
|
521
|
+
用于检测多重共线性问题,返回各变量的VIF值。
|
|
522
|
+
VIF值越大表示共线性越严重,通常VIF > 10表示存在严重共线性。
|
|
523
|
+
|
|
524
|
+
Parameters
|
|
525
|
+
----------
|
|
526
|
+
df : pd.DataFrame
|
|
527
|
+
包含自变量的数据框
|
|
528
|
+
|
|
529
|
+
Returns
|
|
530
|
+
-------
|
|
531
|
+
pd.DataFrame
|
|
532
|
+
包含以下列的数据框:
|
|
533
|
+
- index: 变量名
|
|
534
|
+
- VIF: 方差膨胀因子值
|
|
535
|
+
|
|
536
|
+
Examples
|
|
537
|
+
--------
|
|
538
|
+
>>> vif_result = calculate_vif(X_train)
|
|
539
|
+
>>> high_vif_vars = vif_result[vif_result['VIF'] > 10]['index'].tolist()
|
|
540
|
+
"""
|
|
541
|
+
from statsmodels.stats.outliers_influence import variance_inflation_factor
|
|
542
|
+
|
|
543
|
+
vif = pd.DataFrame()
|
|
544
|
+
vif['index'] = df.columns
|
|
545
|
+
vif['VIF'] = [variance_inflation_factor(df.values, i) for i in range(df.shape[1])]
|
|
546
|
+
return vif
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
# def var_corr_filter(data, varlist, corr_cutpoint=0.8, method='pearson', woe_mapping_table=None, suffix='_woe', ret_winner_var=False):
|
|
571
|
+
# """筛选高相关变量对。
|
|
572
|
+
|
|
573
|
+
# 计算变量间的相关性矩阵,返回超过指定阈值的高相关变量对。
|
|
574
|
+
# 支持基于IV值确定每对中的优质变量。
|
|
575
|
+
|
|
576
|
+
# Parameters
|
|
577
|
+
# ----------
|
|
578
|
+
# data : pd.DataFrame
|
|
579
|
+
# 输入的原始数据框
|
|
580
|
+
# varlist : list
|
|
581
|
+
# 待分析的变量名列表
|
|
582
|
+
# corr_cutpoint : float, optional
|
|
583
|
+
# 相关系数阈值,默认为0.8
|
|
584
|
+
# method : str, optional
|
|
585
|
+
# 相关系数计算方法,默认为'pearson',
|
|
586
|
+
# 可选'pearson'、'spearman'、'kendall'
|
|
587
|
+
# woe_mapping_table : pd.DataFrame, optional
|
|
588
|
+
# WOE映射表,包含VAR和IV列,默认为None
|
|
589
|
+
# suffix : str, optional
|
|
590
|
+
# WOE变量后缀,默认为'_woe'
|
|
591
|
+
# ret_winner_var : bool, optional
|
|
592
|
+
# 是否返回每对中的优质变量,默认为False
|
|
593
|
+
|
|
594
|
+
# Returns
|
|
595
|
+
# -------
|
|
596
|
+
# pd.DataFrame
|
|
597
|
+
# 包含高相关变量对的数据框,列包括:
|
|
598
|
+
# - VAR1: 变量1
|
|
599
|
+
# - VAR2: 变量2
|
|
600
|
+
# - CORR: 相关系数
|
|
601
|
+
# - var1_iv, var2_iv: 变量IV值(当woe_mapping_table不为None时)
|
|
602
|
+
# - winner: 优质变量名(当ret_winner_var=True时)
|
|
603
|
+
|
|
604
|
+
# Examples
|
|
605
|
+
# --------
|
|
606
|
+
# >>> high_corr = var_corr_filter(df, ['var1', 'var2', 'var3'])
|
|
607
|
+
# """
|
|
608
|
+
# corr_matrix = data[varlist].corr(method=method)
|
|
609
|
+
# corr_melt = corr_matrix.reset_index(drop=False).melt(
|
|
610
|
+
# id_vars=["index"],
|
|
611
|
+
# value_vars=[x for x in corr_matrix.columns if x != 'index']
|
|
612
|
+
# )
|
|
613
|
+
# corr_melt = corr_melt.query("index != variable")
|
|
614
|
+
|
|
615
|
+
# if woe_mapping_table is not None:
|
|
616
|
+
# iv_res = woe_mapping_table.groupby(["VAR"]).agg({"IV": "sum"}).reset_index()
|
|
617
|
+
# iv_mapping = dict(zip(iv_res['VAR'], iv_res['IV']))
|
|
618
|
+
# iv_mapping = {k + suffix: v for k, v in iv_mapping.items()}
|
|
619
|
+
# corr_melt["var1_iv"] = corr_melt["index"].map(iv_mapping)
|
|
620
|
+
# corr_melt["var2_iv"] = corr_melt["variable"].map(iv_mapping)
|
|
621
|
+
|
|
622
|
+
# if ret_winner_var:
|
|
623
|
+
# winner_var = corr_melt.apply(
|
|
624
|
+
# lambda row: row[row[['var1_iv', 'var2_iv']].argmax()],
|
|
625
|
+
# axis=1
|
|
626
|
+
# )
|
|
627
|
+
# corr_melt['winner'] = winner_var
|
|
628
|
+
|
|
629
|
+
# corr_melt = corr_melt.query(f"value > {corr_cutpoint}")
|
|
630
|
+
|
|
631
|
+
# # Drop Duplicate Comparison
|
|
632
|
+
# corr_melt['compare_set'] = corr_melt.apply(
|
|
633
|
+
# lambda x: sorted([x['index'], x['variable']]),
|
|
634
|
+
# axis=1
|
|
635
|
+
# )
|
|
636
|
+
# corr_melt = corr_melt.drop_duplicates(subset=['compare_set'], keep='first')
|
|
637
|
+
# corr_melt = corr_melt.drop(columns=['compare_set'])
|
|
638
|
+
|
|
639
|
+
# # Rename Colnames
|
|
640
|
+
# corr_melt.columns = ['VAR1', 'VAR2', 'CORR']
|
|
641
|
+
# return corr_melt.sort_values(["CORR"], ascending=False).reset_index(drop=True)
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
# def remove_corr_var(data, varlist, dep, corr_cutpoint=0.8, method='pearson', tree_binning_seed=None, chi2_config=None):
|
|
647
|
+
# """单次迭代去除高相关变量。
|
|
648
|
+
|
|
649
|
+
# 对变量列表执行一次相关性过滤,基于IV值保留最优质的变量。
|
|
650
|
+
|
|
651
|
+
# Parameters
|
|
652
|
+
# ----------
|
|
653
|
+
# data : pd.DataFrame
|
|
654
|
+
# 输入的原始数据框
|
|
655
|
+
# varlist : list
|
|
656
|
+
# 待筛选的变量名列表
|
|
657
|
+
# dep : str
|
|
658
|
+
# 目标变量(因变量)列名
|
|
659
|
+
# corr_cutpoint : float, optional
|
|
660
|
+
# 相关系数阈值,默认为0.8
|
|
661
|
+
# method : str, optional
|
|
662
|
+
# 相关系数计算方法,默认为'pearson'
|
|
663
|
+
# tree_binning_seed : int, optional
|
|
664
|
+
# 决策树分箱随机种子,默认为None
|
|
665
|
+
# chi2_config : tuple, optional
|
|
666
|
+
# 卡方分箱配置,(init_bins, p_value)元组,默认为None
|
|
667
|
+
|
|
668
|
+
# Returns
|
|
669
|
+
# -------
|
|
670
|
+
# list
|
|
671
|
+
# 筛选后保留的变量名列表
|
|
672
|
+
|
|
673
|
+
# Examples
|
|
674
|
+
# --------
|
|
675
|
+
# >>> keep_vars = remove_corr_var(df, ['var1', 'var2', 'var3'], 'target')
|
|
676
|
+
# """
|
|
677
|
+
# high_corr_var = var_corr_filter(
|
|
678
|
+
# data, varlist,
|
|
679
|
+
# corr_cutpoint=corr_cutpoint,
|
|
680
|
+
# method=method
|
|
681
|
+
# )
|
|
682
|
+
# base_varlist = high_corr_var['VAR1'].drop_duplicates().tolist()
|
|
683
|
+
|
|
684
|
+
# selected_varlist = []
|
|
685
|
+
# removed_varlist = []
|
|
686
|
+
# for var in tqdm(base_varlist):
|
|
687
|
+
# if var not in set(removed_varlist + selected_varlist):
|
|
688
|
+
# single_var_corr = high_corr_var.query(f""" VAR1 == '{var}'""")
|
|
689
|
+
# correlated_list = [var] + single_var_corr['VAR2'].drop_duplicates().tolist()
|
|
690
|
+
|
|
691
|
+
# iv_res = woe_transformation(
|
|
692
|
+
# train_df=data,
|
|
693
|
+
# varlist=correlated_list,
|
|
694
|
+
# dep=dep,
|
|
695
|
+
# oot_df=None,
|
|
696
|
+
# nbins=10,
|
|
697
|
+
# chi2_config=chi2_config,
|
|
698
|
+
# tree_binning_seed=tree_binning_seed,
|
|
699
|
+
# precision=5,
|
|
700
|
+
# min_bin_prop=0.05,
|
|
701
|
+
# include_missing=False,
|
|
702
|
+
# equal_freq=True,
|
|
703
|
+
# fillna=-999999,
|
|
704
|
+
# spec_values=[],
|
|
705
|
+
# drop_bin_info=True,
|
|
706
|
+
# ret_woe_table=True
|
|
707
|
+
# )[1].groupby(["VAR"]).agg({"IV": "sum"})
|
|
708
|
+
# fnl_selected_var = iv_res.reset_index().max()['VAR']
|
|
709
|
+
|
|
710
|
+
# if fnl_selected_var not in selected_varlist:
|
|
711
|
+
# selected_varlist.append(fnl_selected_var)
|
|
712
|
+
|
|
713
|
+
# removed_varlist += [x for x in correlated_list if x != fnl_selected_var and x not in removed_varlist]
|
|
714
|
+
|
|
715
|
+
# other_varlist = [x for x in varlist if x not in (selected_varlist + removed_varlist)]
|
|
716
|
+
# fnl_keep_varlist = selected_varlist + other_varlist
|
|
717
|
+
|
|
718
|
+
# return fnl_keep_varlist
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
# def remove_correlated_vars(data, varlist, dep, corr_cutpoint=0.8, method='pearson', tree_binning_seed=None, chi2_config=None):
|
|
722
|
+
# """迭代去除高相关变量。
|
|
723
|
+
|
|
724
|
+
# 反复执行相关性过滤操作,直到没有变量被移除或达到最大迭代次数。
|
|
725
|
+
# 基于IV值在每组高相关变量中保留最优质的变量。
|
|
726
|
+
|
|
727
|
+
# Parameters
|
|
728
|
+
# ----------
|
|
729
|
+
# data : pd.DataFrame
|
|
730
|
+
# 输入的原始数据框
|
|
731
|
+
# varlist : list
|
|
732
|
+
# 待筛选的变量名列表
|
|
733
|
+
# dep : str
|
|
734
|
+
# 目标变量(因变量)列名
|
|
735
|
+
# corr_cutpoint : float, optional
|
|
736
|
+
# 相关系数阈值,默认为0.8
|
|
737
|
+
# method : str, optional
|
|
738
|
+
# 相关系数计算方法,默认为'pearson'
|
|
739
|
+
# tree_binning_seed : int, optional
|
|
740
|
+
# 决策树分箱随机种子,默认为None
|
|
741
|
+
# chi2_config : tuple, optional
|
|
742
|
+
# 卡方分箱配置,(init_bins, p_value)元组,默认为None
|
|
743
|
+
|
|
744
|
+
# Returns
|
|
745
|
+
# -------
|
|
746
|
+
# list
|
|
747
|
+
# 最终保留的变量名列表
|
|
748
|
+
|
|
749
|
+
# Examples
|
|
750
|
+
# --------
|
|
751
|
+
# >>> keep_vars = remove_correlated_vars(df, ['var1', 'var2', 'var3'], 'target')
|
|
752
|
+
# """
|
|
753
|
+
# filter_analyzer = CorrelationFilter(
|
|
754
|
+
# data, dep,
|
|
755
|
+
# corr_cutpoint=corr_cutpoint,
|
|
756
|
+
# method=method,
|
|
757
|
+
# tree_binning_seed=tree_binning_seed,
|
|
758
|
+
# chi2_config=chi2_config
|
|
759
|
+
# )
|
|
760
|
+
# return filter_analyzer.remove_highly_correlated(varlist)
|
|
761
|
+
|
|
762
|
+
|