SuperModelingFactory 0.6.9__tar.gz → 0.7.0__tar.gz
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.
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Model_Eval_Tool.py +7 -4
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Model_Eval_Tool.pyi +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/evaluate_model.py +91 -59
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/evaluate_model.pyi +2 -2
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/weighted_eval_utils.py +1 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Feature_Screen.py +87 -2
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Screen_Gates.py +102 -9
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/credit_model.py +32 -30
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/feature_validation.py +16 -11
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/field_meta.py +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Monotone_Binner.py +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Monotone_Binner.pyi +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/__init__.py +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/PKG-INFO +2 -2
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/README.md +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/PKG-INFO +2 -2
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/pyproject.toml +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/setup.py +1 -1
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/ExcelMaster/ExcelFormatTool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/ExcelMaster/ExcelMaster.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/ExcelMaster/Template.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/ExcelMaster/Utility.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/ExcelMaster/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/LICENSE +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/MANIFEST.in +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Binning_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Binning_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Check_DuckDB_Compatibility.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Json_Data_Converter.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Model_Registry_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/ODPS_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Parallel_Engine.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Parallel_ODPS_Manager.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Proc_Compare.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Slope_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/Slope_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/XOR_Encryptor.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/XOR_Encryptor.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/kDataFrame.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/kDataFrame.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/sample_weight_utils.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Core/utils.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Evaluation_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Evaluation_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Explainability/Coalition_Structure.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Explainability/Model_Explainer.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Explainability/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Distribution_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Distribution_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Feature_Insights.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Feature_Insights.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/ODPS_Distribution_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/ODPS_Distribution_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/PSI_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/PSI_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/WOE_Engine_Feature_Patch.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Weighted_Screen.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/Backward_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/Backward_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/GBM_Search_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/GBM_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/GBM_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/LRM_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/LRM_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Model/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/_common.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/mock_sample.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/orchestrator.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/reject_inference.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/sample_analysis.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/score_comparison.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/score_consistency_uat.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Pipeline/screening_artifact.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Distribution_Adaptation.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Distribution_Adaptation.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Reject_Infer.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Reject_Infer.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Sample_Split.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/Sample_Split.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Sample/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/UAT/UAT_Consistency_Checker.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/UAT/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Adapter.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Adapter.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Master.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Master.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Plot_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Plot_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Report_Builder.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Report_Builder.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/WOE_Tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/plot_woe_tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/WOE/plot_woe_tool.pyi +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/_utils/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/_utils/nan_guard.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/_utils/robust.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/_utils/sentinels.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/ref_font/KaiTi.ttf +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/ref_font/WeiRuanYaHei.ttf +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/ref_font/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/ref_font/simsun.ttc +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Report/Report_Tool.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Report/__init__.py +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/SOURCES.txt +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/dependency_links.txt +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/not-zip-safe +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/requires.txt +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/SuperModelingFactory.egg-info/top_level.txt +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/requirements.txt +0 -0
- {supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/setup.cfg +0 -0
{supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Model_Eval_Tool.py
RENAMED
|
@@ -846,6 +846,7 @@ def get_gains_table(data, dep, nbins = 10, precision = 5, min_bin_prop = 0.05, i
|
|
|
846
846
|
nbins=nbins,
|
|
847
847
|
weight_col=weight_col,
|
|
848
848
|
weighted_binning=weighted_binning,
|
|
849
|
+
ascending=ascending,
|
|
849
850
|
)
|
|
850
851
|
if retSummary:
|
|
851
852
|
return pd.DataFrame({
|
|
@@ -2228,8 +2229,8 @@ class PerformanceEvaluator:
|
|
|
2228
2229
|
# spec_values: sentinel scores (e.g. -1 for all-missing overrides)
|
|
2229
2230
|
# that get their own evaluation bin and are excluded from quantile
|
|
2230
2231
|
# edges and ranking metrics. ascending: None keeps every underlying
|
|
2231
|
-
# function's
|
|
2232
|
-
# summary
|
|
2232
|
+
# function's legacy direction; an explicit bool is threaded through
|
|
2233
|
+
# summary, gains, and figures (including weighted paths) uniformly.
|
|
2233
2234
|
self.spec_values = list(spec_values) if spec_values else []
|
|
2234
2235
|
self.ascending = ascending
|
|
2235
2236
|
self.datasets = {}
|
|
@@ -2420,6 +2421,7 @@ class PerformanceEvaluator:
|
|
|
2420
2421
|
save_path=fig_save_path,
|
|
2421
2422
|
gains_table=gains_table,
|
|
2422
2423
|
equal_freq=self.equal_freq,
|
|
2424
|
+
ascending=self.ascending,
|
|
2423
2425
|
)
|
|
2424
2426
|
if rpt_save_path:
|
|
2425
2427
|
fnl_df.to_csv(rpt_save_path, index=False)
|
|
@@ -2522,7 +2524,7 @@ class PerformanceEvaluator:
|
|
|
2522
2524
|
tree_binning = self.tree_binning,
|
|
2523
2525
|
random_state = self.random_state,
|
|
2524
2526
|
return_edges = True,
|
|
2525
|
-
ascending = True
|
|
2527
|
+
ascending = True if self.ascending is None else bool(self.ascending)
|
|
2526
2528
|
)
|
|
2527
2529
|
|
|
2528
2530
|
if benchmark_bin_edges is None or len(benchmark_bin_edges) < 2:
|
|
@@ -2556,7 +2558,8 @@ class PerformanceEvaluator:
|
|
|
2556
2558
|
save_path = save_path,
|
|
2557
2559
|
gains_table = gains_table,
|
|
2558
2560
|
equal_freq = self.equal_freq,
|
|
2559
|
-
pct_bin_edges = benchmark_bin_edges
|
|
2561
|
+
pct_bin_edges = benchmark_bin_edges,
|
|
2562
|
+
ascending = self.ascending,
|
|
2560
2563
|
)
|
|
2561
2564
|
|
|
2562
2565
|
import re
|
{supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/Model_Eval_Tool.pyi
RENAMED
|
@@ -20,7 +20,7 @@ import pandas as pd
|
|
|
20
20
|
from Modeling_Tool.Core.Binning_Tool import get_bin_range_list, super_binning
|
|
21
21
|
from Modeling_Tool.Core.utils import load_model, calc_iv, calc_woe
|
|
22
22
|
from .evaluate_model import evaluate_performance
|
|
23
|
-
def get_gains_table(data, dep, nbins = 10, precision = 5, min_bin_prop = 0.05, include_missing = True, score = None, model = None, varlist = None, equal_freq = True, chi2_method = False, grp_name = None, min_data_size = 100, grp_colname = None, sync_range = True, chi2_p = 0.95, init_equi_bins = 100, fillna = -999999, spec_values = [], retSummary = False, tree_binning = False, random_state = 42, ascending = False, withSummary = False, wholeGroup = False, add_func = None): ...
|
|
23
|
+
def get_gains_table(data, dep, nbins = 10, precision = 5, min_bin_prop = 0.05, include_missing = True, score = None, model = None, varlist = None, equal_freq = True, chi2_method = False, grp_name = None, min_data_size = 100, grp_colname = None, sync_range = True, chi2_p = 0.95, init_equi_bins = 100, fillna = -999999, spec_values = [], retSummary = False, tree_binning = False, random_state = 42, ascending = False, withSummary = False, wholeGroup = False, add_func = None, weight_col = None, weighted_binning = None): ...
|
|
24
24
|
def get_perf_summary(train, validation, oot, tgt_name, scr_name = None, model = None, feature_cols = None, fig_save_path = None, rpt_save_path = None, to_show = False, display = True, dist_bins = 20, pct_bins = 10, precision = 5, min_bin_prop = 0.05, include_missing = False, equal_freq = True, chi2_method = False, init_equi_bins = 1000, chi2_p = 0.9, oot_grp_name = None, min_data_size = 100, grp_colname = None, tree_binning = False, random_state = 42, gains_table = False): ...
|
|
25
25
|
def cross_risk(data, score_list, dep, nbins, agg_col = None, precision = 5, min_bin_prop = 0.05, include_missing = False, equal_freq = True, binning_numeric = [True, True], agg_func = 'mean', chi2_method = False, chi2_p = 0.95, init_equi_bins = 100, fillna = -999999, spec_values = [], tree_binning = False, random_state = 42): ...
|
|
26
26
|
def get_gains_table_by_cust_metrics(data, dep, nbins = 10, precision = 5, min_bin_prop = 0.05, include_missing = True, score = None, model = None, varlist = None, equal_freq = True, chi2_method = False, grp_name = None, min_data_size = 100, grp_colname = None, sync_range = True, chi2_p = 0.95, init_equi_bins = 100, fillna = -999999, spec_values = [], tree_binning = False, random_state = 42, ascending = True, eval_metrics = ['age', 'monthly_income', 'education'], metric_agg_func = 'mean', withSummary = False): ...
|
{supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/evaluate_model.py
RENAMED
|
@@ -889,7 +889,13 @@ def calc_equid_pct(y_true, y_score, y_group=None, bins=10, ascending=True, sampl
|
|
|
889
889
|
等分分组后各组统计量数据集
|
|
890
890
|
"""
|
|
891
891
|
if sample_weight is not None:
|
|
892
|
-
return _weighted_eval.calc_equid_pct(
|
|
892
|
+
return _weighted_eval.calc_equid_pct(
|
|
893
|
+
y_true,
|
|
894
|
+
y_score,
|
|
895
|
+
bins=bins,
|
|
896
|
+
ascending=ascending,
|
|
897
|
+
sample_weight=sample_weight,
|
|
898
|
+
)
|
|
893
899
|
|
|
894
900
|
y_true = np.array(y_true)
|
|
895
901
|
y_score = np.array(y_score)
|
|
@@ -947,7 +953,12 @@ def calc_fixed_pct(y_true, y_score, y_group=None, bin_edges=None, ascending=True
|
|
|
947
953
|
固定分箱后各组统计量数据集
|
|
948
954
|
"""
|
|
949
955
|
if sample_weight is not None:
|
|
950
|
-
return _weighted_eval.calc_fixed_pct(
|
|
956
|
+
return _weighted_eval.calc_fixed_pct(
|
|
957
|
+
y_true,
|
|
958
|
+
y_score,
|
|
959
|
+
ascending=ascending,
|
|
960
|
+
sample_weight=sample_weight,
|
|
961
|
+
)
|
|
951
962
|
|
|
952
963
|
if bin_edges is None:
|
|
953
964
|
raise ValueError("bin_edges cannot be None when using fixed pct bins.")
|
|
@@ -1007,20 +1018,27 @@ def summarize_pct(pct_df, ascending=True):
|
|
|
1007
1018
|
bins = pct_df.shape[0]
|
|
1008
1019
|
interval = 100 / pct_df.shape[0]
|
|
1009
1020
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
'
|
|
1022
|
-
'
|
|
1023
|
-
}
|
|
1021
|
+
pct_info = {
|
|
1022
|
+
'pct_bins': bins,
|
|
1023
|
+
'pct_interval': interval,
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
# Precomputed gain frames historically only needed thresholds, gain, and
|
|
1027
|
+
# capture_rate. Keep summarize_pct usable for those frames while exposing
|
|
1028
|
+
# target-rate summary keys whenever the richer percentile schema is used.
|
|
1029
|
+
if 'avg_true' in pct_df.columns:
|
|
1030
|
+
top_idx, btm_idx = (bins - 1, 0) if ascending else (0, bins - 1)
|
|
1031
|
+
pct_info.update({
|
|
1032
|
+
'pct_top_avgTrue'.format(interval): pct_df['avg_true'].iloc[top_idx],
|
|
1033
|
+
'pct_btm_avgTrue'.format(interval): pct_df['avg_true'].iloc[btm_idx],
|
|
1034
|
+
})
|
|
1035
|
+
|
|
1036
|
+
if not ascending and 'capture_rate' in pct_df.columns:
|
|
1037
|
+
# Preserve the historical descending-summary keys for direct callers.
|
|
1038
|
+
pct_info.update({
|
|
1039
|
+
'pct_top_captureRate'.format(interval): pct_df['capture_rate'].iloc[bins-1],
|
|
1040
|
+
'pct_btm_captureRate'.format(interval): pct_df['capture_rate'].iloc[0],
|
|
1041
|
+
})
|
|
1024
1042
|
|
|
1025
1043
|
return pct_info
|
|
1026
1044
|
|
|
@@ -1374,7 +1392,7 @@ def __plot_pct_axes_base(ax, fontdicts):
|
|
|
1374
1392
|
ax.set_ylabel('Target rate', fontdict=fontdicts['axislabel'])
|
|
1375
1393
|
|
|
1376
1394
|
|
|
1377
|
-
def __plot_single_pct_axes(pct_df, ax, fontdicts):
|
|
1395
|
+
def __plot_single_pct_axes(pct_df, ax, fontdicts, ascending=True):
|
|
1378
1396
|
"""在axes上绘制单个Score分布图.
|
|
1379
1397
|
|
|
1380
1398
|
Parameters
|
|
@@ -1397,7 +1415,7 @@ def __plot_single_pct_axes(pct_df, ax, fontdicts):
|
|
|
1397
1415
|
ax.plot(X, pct_df['avg_true'], color=palette['ClassicBlueRedGrey'][1], linewidth=2, marker='.', markersize=5, label='True')
|
|
1398
1416
|
ax.axhline(y=pct_df['cumavg_true'][pct_df.shape[0]-1], linestyle='--', color=palette['ClassicBlueRedGrey'][2], linewidth=2, label='Random')
|
|
1399
1417
|
|
|
1400
|
-
pct_info = summarize_pct(pct_df)
|
|
1418
|
+
pct_info = summarize_pct(pct_df, ascending=ascending)
|
|
1401
1419
|
_b, _i, _top, _btm = pct_info['pct_bins'], pct_info['pct_interval'], pct_info['pct_top_avgTrue'], pct_info['pct_btm_avgTrue']
|
|
1402
1420
|
ax.set_title("Bins={0} Top{1:.0f}%={2:.2%} BTM{1:.0f}%={3:.2%}".format(_b, _i, _top, _btm), fontdict=fontdicts['subtitle'])
|
|
1403
1421
|
ax.legend(loc=2, fontsize=fontdicts['legend']['size'])
|
|
@@ -1524,7 +1542,7 @@ def __plot_multi_cumpct_axes(pct_dfs, ax, fontdicts):
|
|
|
1524
1542
|
|
|
1525
1543
|
# Gain Curve
|
|
1526
1544
|
@timeit_decorator
|
|
1527
|
-
def plot_gain_curve(pct_dfs, square_figsize=8, fontdicts=fontdicts['main'], to_show=True, save_path=None):
|
|
1545
|
+
def plot_gain_curve(pct_dfs, square_figsize=8, fontdicts=fontdicts['main'], to_show=True, save_path=None, ascending=False):
|
|
1528
1546
|
"""绘制Score分布曲线图.
|
|
1529
1547
|
|
|
1530
1548
|
Parameters
|
|
@@ -1537,6 +1555,8 @@ def plot_gain_curve(pct_dfs, square_figsize=8, fontdicts=fontdicts['main'], to_s
|
|
|
1537
1555
|
是否展示图片. 默认为True
|
|
1538
1556
|
save_path: str
|
|
1539
1557
|
结果图片存放文件地址. 默认值为None, 即不保存
|
|
1558
|
+
ascending: bool, default False
|
|
1559
|
+
Gain 图按分数升序(True)或降序(False)累计。
|
|
1540
1560
|
"""
|
|
1541
1561
|
plt.figure(figsize=(square_figsize, square_figsize))
|
|
1542
1562
|
plt.suptitle('Gain Curve', fontsize=fontdicts['suptitle']['size'], fontweight=fontdicts['suptitle']['weight']) #, findfont=zhfont)
|
|
@@ -1545,9 +1565,9 @@ def plot_gain_curve(pct_dfs, square_figsize=8, fontdicts=fontdicts['main'], to_s
|
|
|
1545
1565
|
models = list(pct_dfs.keys())
|
|
1546
1566
|
if len(models) == 1:
|
|
1547
1567
|
pct_df = pct_dfs[models[0]]
|
|
1548
|
-
__plot_single_gain_axes(pct_df, ax, fontdicts)
|
|
1568
|
+
__plot_single_gain_axes(pct_df, ax, fontdicts, ascending=ascending)
|
|
1549
1569
|
else:
|
|
1550
|
-
__plot_multi_gain_axes(pct_dfs, ax, fontdicts)
|
|
1570
|
+
__plot_multi_gain_axes(pct_dfs, ax, fontdicts, ascending=ascending)
|
|
1551
1571
|
ax.legend(loc=2, fontsize=fontdicts['legend']['size'])
|
|
1552
1572
|
|
|
1553
1573
|
if to_show:
|
|
@@ -1557,7 +1577,7 @@ def plot_gain_curve(pct_dfs, square_figsize=8, fontdicts=fontdicts['main'], to_s
|
|
|
1557
1577
|
plt.close()
|
|
1558
1578
|
|
|
1559
1579
|
|
|
1560
|
-
def __plot_gain_axes_base(ax, fontdicts):
|
|
1580
|
+
def __plot_gain_axes_base(ax, fontdicts, ascending=False):
|
|
1561
1581
|
"""在axes上绘制Score分布图基础.
|
|
1562
1582
|
|
|
1563
1583
|
Parameters
|
|
@@ -1570,11 +1590,12 @@ def __plot_gain_axes_base(ax, fontdicts):
|
|
|
1570
1590
|
ax.plot([0,100], [0,1], color='k', linestyle='--', linewidth=1)
|
|
1571
1591
|
ax.set_xlim([0,100])
|
|
1572
1592
|
ax.set_ylim([0,1])
|
|
1573
|
-
|
|
1593
|
+
direction = 'Ascending' if ascending else 'Descending'
|
|
1594
|
+
ax.set_xlabel(f'Percentile % (Score {direction})', fontdict=fontdicts['axislabel'])
|
|
1574
1595
|
ax.set_ylabel('gain', fontdict=fontdicts['axislabel'])
|
|
1575
1596
|
|
|
1576
1597
|
|
|
1577
|
-
def __plot_single_gain_axes(pct_df, ax, fontdicts):
|
|
1598
|
+
def __plot_single_gain_axes(pct_df, ax, fontdicts, ascending=False):
|
|
1578
1599
|
"""在axes上绘制单个Score分布图.
|
|
1579
1600
|
|
|
1580
1601
|
Parameters
|
|
@@ -1586,11 +1607,11 @@ def __plot_single_gain_axes(pct_df, ax, fontdicts):
|
|
|
1586
1607
|
fontdicts: dict
|
|
1587
1608
|
绘图相关字体字典
|
|
1588
1609
|
"""
|
|
1589
|
-
__plot_gain_axes_base(ax, fontdicts)
|
|
1610
|
+
__plot_gain_axes_base(ax, fontdicts, ascending=ascending)
|
|
1590
1611
|
|
|
1591
1612
|
plot_df = pct_df.copy()
|
|
1592
1613
|
if {'avg_score', 'proportion', 'capture_rate'}.issubset(plot_df.columns):
|
|
1593
|
-
plot_df = plot_df.sort_values('avg_score', ascending=
|
|
1614
|
+
plot_df = plot_df.sort_values('avg_score', ascending=ascending).reset_index(drop=True)
|
|
1594
1615
|
plot_df['thresholds'] = plot_df['proportion'].cumsum() * 100
|
|
1595
1616
|
plot_df['gain'] = plot_df['capture_rate'].cumsum()
|
|
1596
1617
|
|
|
@@ -1600,14 +1621,15 @@ def __plot_single_gain_axes(pct_df, ax, fontdicts):
|
|
|
1600
1621
|
Y = np.insert(Y, 0, 0)
|
|
1601
1622
|
ax.plot(X, Y, color=palette['ClassicBlueRedGrey'][0], linewidth=2, marker='.', markersize=5, label='avgScore')
|
|
1602
1623
|
|
|
1603
|
-
pct_info = summarize_pct(plot_df, ascending=
|
|
1624
|
+
pct_info = summarize_pct(plot_df, ascending=ascending)
|
|
1604
1625
|
_b, _i = pct_info['pct_bins'], pct_info['pct_interval']
|
|
1605
|
-
|
|
1606
|
-
|
|
1626
|
+
_top_idx, _btm_idx = (-1, 0) if ascending else (0, -1)
|
|
1627
|
+
_top = plot_df['capture_rate'].iloc[_top_idx] if plot_df.shape[0] > 0 else np.nan
|
|
1628
|
+
_btm = plot_df['capture_rate'].iloc[_btm_idx] if plot_df.shape[0] > 0 else np.nan
|
|
1607
1629
|
ax.set_title("Bins={0} Top{1:.0f}%={2:.2%} BTM{1:.0f}%={3:.2%}".format(_b, _i, _top, _btm), fontdict=fontdicts['subtitle'])
|
|
1608
1630
|
|
|
1609
1631
|
|
|
1610
|
-
def __plot_multi_gain_axes(pct_dfs, ax, fontdicts):
|
|
1632
|
+
def __plot_multi_gain_axes(pct_dfs, ax, fontdicts, ascending=False):
|
|
1611
1633
|
"""在axes上绘制多个Score分布图.
|
|
1612
1634
|
|
|
1613
1635
|
Parameters
|
|
@@ -1619,14 +1641,14 @@ def __plot_multi_gain_axes(pct_dfs, ax, fontdicts):
|
|
|
1619
1641
|
fontdicts: dict
|
|
1620
1642
|
绘图相关字体字典
|
|
1621
1643
|
"""
|
|
1622
|
-
__plot_gain_axes_base(ax, fontdicts)
|
|
1644
|
+
__plot_gain_axes_base(ax, fontdicts, ascending=ascending)
|
|
1623
1645
|
|
|
1624
1646
|
models = list(pct_dfs.keys())
|
|
1625
1647
|
for i in range(len(models)):
|
|
1626
1648
|
md = models[i]
|
|
1627
1649
|
pct_df = pct_dfs[md].copy()
|
|
1628
1650
|
if {'avg_score', 'proportion', 'capture_rate'}.issubset(pct_df.columns):
|
|
1629
|
-
pct_df = pct_df.sort_values('avg_score', ascending=
|
|
1651
|
+
pct_df = pct_df.sort_values('avg_score', ascending=ascending).reset_index(drop=True)
|
|
1630
1652
|
pct_df['thresholds'] = pct_df['proportion'].cumsum() * 100
|
|
1631
1653
|
pct_df['gain'] = pct_df['capture_rate'].cumsum()
|
|
1632
1654
|
X = np.array(pct_df['thresholds'])
|
|
@@ -1636,7 +1658,7 @@ def __plot_multi_gain_axes(pct_dfs, ax, fontdicts):
|
|
|
1636
1658
|
ax.plot(X, Y, color=palette['MorandiDark'][i], linewidth=2, marker='.', markersize=5, label='{0} avgTrue'.format(md))
|
|
1637
1659
|
|
|
1638
1660
|
|
|
1639
|
-
def _weighted_gains_to_plot_frames(weighted_gains):
|
|
1661
|
+
def _weighted_gains_to_plot_frames(weighted_gains, pct_ascending=True, gain_ascending=False):
|
|
1640
1662
|
"""Convert weighted gains output into the plotting helpers' long schema."""
|
|
1641
1663
|
if weighted_gains is None or weighted_gains.empty:
|
|
1642
1664
|
return pd.DataFrame(), pd.DataFrame()
|
|
@@ -1646,8 +1668,8 @@ def _weighted_gains_to_plot_frames(weighted_gains):
|
|
|
1646
1668
|
if missing:
|
|
1647
1669
|
raise KeyError(f"Weighted gains table missing plotting columns: {missing}")
|
|
1648
1670
|
|
|
1649
|
-
|
|
1650
|
-
total_bad = float(
|
|
1671
|
+
gains = weighted_gains.reset_index(drop=True).copy()
|
|
1672
|
+
total_bad = float(gains["N_BAD"].sum())
|
|
1651
1673
|
|
|
1652
1674
|
def _convert(source):
|
|
1653
1675
|
source = source.reset_index(drop=True)
|
|
@@ -1680,10 +1702,10 @@ def _weighted_gains_to_plot_frames(weighted_gains):
|
|
|
1680
1702
|
}
|
|
1681
1703
|
)
|
|
1682
1704
|
|
|
1683
|
-
#
|
|
1684
|
-
#
|
|
1685
|
-
percentile_frame = _convert(
|
|
1686
|
-
gain_frame = _convert(
|
|
1705
|
+
# An explicit direction governs both plots. The optional defaults retain
|
|
1706
|
+
# the historical mixed behavior for direct callers that leave it unset.
|
|
1707
|
+
percentile_frame = _convert(gains.sort_values("AVG_SCORE", ascending=pct_ascending))
|
|
1708
|
+
gain_frame = _convert(gains.sort_values("AVG_SCORE", ascending=gain_ascending))
|
|
1687
1709
|
return percentile_frame, gain_frame
|
|
1688
1710
|
|
|
1689
1711
|
|
|
@@ -1696,7 +1718,7 @@ def _set_weighted_axis_title(ax, fontdicts):
|
|
|
1696
1718
|
|
|
1697
1719
|
|
|
1698
1720
|
@timeit_decorator
|
|
1699
|
-
def evaluate_performance(datasets, dist_bins=20, pct_bins=10, square_figsize=5, fontdicts=fontdicts['sub'], to_show=True, save_path=None, gains_table = True, equal_freq = True, pct_bin_edges = None, sample_weight=None):
|
|
1721
|
+
def evaluate_performance(datasets, dist_bins=20, pct_bins=10, square_figsize=5, fontdicts=fontdicts['sub'], to_show=True, save_path=None, gains_table = True, equal_freq = True, pct_bin_edges = None, sample_weight=None, ascending=None):
|
|
1700
1722
|
"""绘制单模型预测效果评价图.
|
|
1701
1723
|
|
|
1702
1724
|
Parameters
|
|
@@ -1715,6 +1737,9 @@ def evaluate_performance(datasets, dist_bins=20, pct_bins=10, square_figsize=5,
|
|
|
1715
1737
|
是否展示图片. 默认为True
|
|
1716
1738
|
save_path: str
|
|
1717
1739
|
结果图片存放文件地址. 默认值为None, 即不保存
|
|
1740
|
+
ascending: bool, optional
|
|
1741
|
+
显式值统一控制收益表、百分位图和 Gain 图的分数方向;None 保留
|
|
1742
|
+
历史百分位升序、Gain 降序的行为。
|
|
1718
1743
|
|
|
1719
1744
|
Returns
|
|
1720
1745
|
-------
|
|
@@ -1746,7 +1771,7 @@ def evaluate_performance(datasets, dist_bins=20, pct_bins=10, square_figsize=5,
|
|
|
1746
1771
|
y_true = datasets[d]['y_true']
|
|
1747
1772
|
y_score = datasets[d]['y_score']
|
|
1748
1773
|
dataset_weight = datasets[d].get('sample_weight', sample_weight)
|
|
1749
|
-
result.update({d: __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins, fontdicts, gains_table, equal_freq, pct_bin_edges, sample_weight=dataset_weight)})
|
|
1774
|
+
result.update({d: __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins, fontdicts, gains_table, equal_freq, pct_bin_edges, sample_weight=dataset_weight, ascending=ascending)})
|
|
1750
1775
|
|
|
1751
1776
|
result_df = pd.DataFrame.from_dict(result, orient='index').reset_index()
|
|
1752
1777
|
|
|
@@ -1779,7 +1804,7 @@ def resturct_gains(gains_table):
|
|
|
1779
1804
|
|
|
1780
1805
|
return gains_table
|
|
1781
1806
|
|
|
1782
|
-
def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins, fontdicts, gains_table = True, equal_freq = True, pct_bin_edges = None, sample_weight=None):
|
|
1807
|
+
def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins, fontdicts, gains_table = True, equal_freq = True, pct_bin_edges = None, sample_weight=None, ascending=None):
|
|
1783
1808
|
"""绘制单模型在单样本集上预测效果评价图.
|
|
1784
1809
|
包括: ROC、KDE、PCT、Gain四图.
|
|
1785
1810
|
|
|
@@ -1806,6 +1831,13 @@ def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins,
|
|
|
1806
1831
|
# from Model_Eval_Tool import get_gains_table
|
|
1807
1832
|
from .Model_Eval_Tool import get_gains_table
|
|
1808
1833
|
|
|
1834
|
+
# ``None`` preserves the historical PCT-ascending / gain-descending
|
|
1835
|
+
# split. An explicit bool applies one direction consistently.
|
|
1836
|
+
pct_ascending = True if ascending is None else bool(ascending)
|
|
1837
|
+
gain_ascending = False if ascending is None else bool(ascending)
|
|
1838
|
+
unweighted_gains_ascending = True if ascending is None else bool(ascending)
|
|
1839
|
+
weighted_gains_ascending = False if ascending is None else bool(ascending)
|
|
1840
|
+
|
|
1809
1841
|
# 清理数据
|
|
1810
1842
|
mask = np.isfinite(y_score) & np.isfinite(y_true)
|
|
1811
1843
|
if sample_weight is not None:
|
|
@@ -1832,7 +1864,7 @@ def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins,
|
|
|
1832
1864
|
include_missing = False,
|
|
1833
1865
|
score = 'y_score',
|
|
1834
1866
|
equal_freq = equal_freq,
|
|
1835
|
-
ascending =
|
|
1867
|
+
ascending = unweighted_gains_ascending,
|
|
1836
1868
|
withSummary = False,
|
|
1837
1869
|
weight_col = '_sample_weight' if sample_weight is not None else None,
|
|
1838
1870
|
)
|
|
@@ -1847,28 +1879,28 @@ def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins,
|
|
|
1847
1879
|
"y_score",
|
|
1848
1880
|
nbins=bin_count,
|
|
1849
1881
|
weight_col="w",
|
|
1882
|
+
ascending=weighted_gains_ascending,
|
|
1883
|
+
)
|
|
1884
|
+
pct_df, pct_desc_df = _weighted_gains_to_plot_frames(
|
|
1885
|
+
weighted_gains,
|
|
1886
|
+
pct_ascending=pct_ascending,
|
|
1887
|
+
gain_ascending=gain_ascending,
|
|
1850
1888
|
)
|
|
1851
|
-
pct_df, pct_desc_df = _weighted_gains_to_plot_frames(weighted_gains)
|
|
1852
1889
|
if gains_table:
|
|
1853
1890
|
y_gains = weighted_gains
|
|
1854
|
-
pct_info =
|
|
1855
|
-
"pct_bins": weighted_gains.shape[0],
|
|
1856
|
-
"pct_interval": 100.0 / weighted_gains.shape[0] if weighted_gains.shape[0] else np.nan,
|
|
1857
|
-
"pct_top_avgTrue": float(weighted_gains["AVG_BAD"].iloc[0]) if len(weighted_gains) else np.nan,
|
|
1858
|
-
"pct_btm_avgTrue": float(weighted_gains["AVG_BAD"].iloc[-1]) if len(weighted_gains) else np.nan,
|
|
1859
|
-
}
|
|
1891
|
+
pct_info = summarize_pct(pct_df, ascending=pct_ascending)
|
|
1860
1892
|
else:
|
|
1861
1893
|
if pct_bin_edges is not None:
|
|
1862
|
-
pct_df = calc_fixed_pct(y_true, y_score, None, bin_edges=pct_bin_edges, ascending=
|
|
1894
|
+
pct_df = calc_fixed_pct(y_true, y_score, None, bin_edges=pct_bin_edges, ascending=pct_ascending, sample_weight=sample_weight)
|
|
1863
1895
|
else:
|
|
1864
|
-
pct_df = calc_equid_pct(y_true, y_score, None, bins=pct_bins, sample_weight=sample_weight)
|
|
1896
|
+
pct_df = calc_equid_pct(y_true, y_score, None, bins=pct_bins, ascending=pct_ascending, sample_weight=sample_weight)
|
|
1865
1897
|
|
|
1866
1898
|
if gains_table:
|
|
1867
1899
|
pct_index = pct_df["thresholds"]
|
|
1868
1900
|
pct_df = resturct_gains(y_gains)
|
|
1869
1901
|
pct_df["thresholds"] = pct_index
|
|
1870
1902
|
|
|
1871
|
-
pct_info = summarize_pct(pct_df, ascending=
|
|
1903
|
+
pct_info = summarize_pct(pct_df, ascending=pct_ascending)
|
|
1872
1904
|
|
|
1873
1905
|
if len(y_true) < 2 or len(np.unique(y_true)) < 2:
|
|
1874
1906
|
# 返回默认性能指标(全部为NaN)
|
|
@@ -1884,9 +1916,9 @@ def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins,
|
|
|
1884
1916
|
|
|
1885
1917
|
if sample_weight is None:
|
|
1886
1918
|
if pct_bin_edges is not None:
|
|
1887
|
-
pct_desc_df = calc_fixed_pct(y_true, y_score, None, bin_edges=pct_bin_edges, ascending=
|
|
1919
|
+
pct_desc_df = calc_fixed_pct(y_true, y_score, None, bin_edges=pct_bin_edges, ascending=gain_ascending, sample_weight=sample_weight)
|
|
1888
1920
|
else:
|
|
1889
|
-
pct_desc_df = calc_equid_pct(y_true, y_score, None, bins=pct_bins, ascending=
|
|
1921
|
+
pct_desc_df = calc_equid_pct(y_true, y_score, None, bins=pct_bins, ascending=gain_ascending, sample_weight=sample_weight)
|
|
1890
1922
|
|
|
1891
1923
|
ax_roc = plt.subplot(nrow, ncol, i*ncol+1)
|
|
1892
1924
|
__plot_single_roc_axes(roc_df, ax_roc, fontdicts)
|
|
@@ -1900,16 +1932,16 @@ def __evaluate_performance(y_true, y_score, nrow, ncol, i, dist_bins, pct_bins,
|
|
|
1900
1932
|
sample_weight=sample_weight,
|
|
1901
1933
|
)
|
|
1902
1934
|
if sample_weight is None:
|
|
1903
|
-
__plot_single_pct_axes(pct_df, plt.subplot(nrow, ncol, i*ncol+3), fontdicts)
|
|
1904
|
-
__plot_single_gain_axes(pct_desc_df, plt.subplot(nrow, ncol, i*ncol+4), fontdicts)
|
|
1935
|
+
__plot_single_pct_axes(pct_df, plt.subplot(nrow, ncol, i*ncol+3), fontdicts, ascending=pct_ascending)
|
|
1936
|
+
__plot_single_gain_axes(pct_desc_df, plt.subplot(nrow, ncol, i*ncol+4), fontdicts, ascending=gain_ascending)
|
|
1905
1937
|
else:
|
|
1906
1938
|
_set_weighted_axis_title(ax_roc, fontdicts)
|
|
1907
1939
|
_set_weighted_axis_title(ax_kde, fontdicts)
|
|
1908
1940
|
ax_pct = plt.subplot(nrow, ncol, i * ncol + 3)
|
|
1909
|
-
__plot_single_pct_axes(pct_df, ax_pct, fontdicts)
|
|
1941
|
+
__plot_single_pct_axes(pct_df, ax_pct, fontdicts, ascending=pct_ascending)
|
|
1910
1942
|
_set_weighted_axis_title(ax_pct, fontdicts)
|
|
1911
1943
|
ax_gain = plt.subplot(nrow, ncol, i * ncol + 4)
|
|
1912
|
-
__plot_single_gain_axes(pct_desc_df, ax_gain, fontdicts)
|
|
1944
|
+
__plot_single_gain_axes(pct_desc_df, ax_gain, fontdicts, ascending=gain_ascending)
|
|
1913
1945
|
_set_weighted_axis_title(ax_gain, fontdicts)
|
|
1914
1946
|
|
|
1915
1947
|
info = {
|
{supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Eval/evaluate_model.pyi
RENAMED
|
@@ -42,8 +42,8 @@ def plot_dist_curve(dist_dfs, square_figsize = 8, fontdicts = fontdicts['main'],
|
|
|
42
42
|
def plot_cumdist_curve(dist_dfs, square_figsize = 8, fontdicts = fontdicts['main'], to_show = True, save_path = None): ...
|
|
43
43
|
def plot_pct_curve(pct_dfs, square_figsize = 8, fontdicts = fontdicts['main'], to_show = True, save_path = None): ...
|
|
44
44
|
def plot_cumpct_curve(pct_dfs, square_figsize = 8, fontdicts = fontdicts['main'], to_show = True, save_path = None): ...
|
|
45
|
-
def plot_gain_curve(pct_dfs, square_figsize = 8, fontdicts = fontdicts['main'], to_show = True, save_path = None): ...
|
|
46
|
-
def evaluate_performance(datasets, dist_bins = 20, pct_bins = 10, square_figsize = 5, fontdicts = fontdicts['sub'], to_show = True, save_path = None, gains_table = True, equal_freq = True, pct_bin_edges = None): ...
|
|
45
|
+
def plot_gain_curve(pct_dfs, square_figsize = 8, fontdicts = fontdicts['main'], to_show = True, save_path = None, ascending = False): ...
|
|
46
|
+
def evaluate_performance(datasets, dist_bins = 20, pct_bins = 10, square_figsize = 5, fontdicts = fontdicts['sub'], to_show = True, save_path = None, gains_table = True, equal_freq = True, pct_bin_edges = None, sample_weight = None, ascending = None): ...
|
|
47
47
|
def resturct_gains(gains_table): ...
|
|
48
48
|
def evaluate_distribution(datasets, dist_bins = 10, square_figsize = 5, fontdicts = fontdicts['sub'], toplot = True, save_path = None): ...
|
|
49
49
|
def comparison_performance(datasets, pct_bins = 10, square_figsize = 5, fontdicts = fontdicts['sub'], to_show = True, save_path = None): ...
|
{supermodelingfactory-0.6.9 → supermodelingfactory-0.7.0}/Modeling_Tool/Feature/Feature_Screen.py
RENAMED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import warnings
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any, Literal, Mapping
|
|
8
|
+
from typing import Any, Callable, Literal, Mapping
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
import pandas as pd
|
|
@@ -113,6 +113,11 @@ class FeatureScreenConfig:
|
|
|
113
113
|
vif_threshold: float = 10.0
|
|
114
114
|
vif_min_features: int = 2
|
|
115
115
|
vif_tie_break_metric: str = "iv"
|
|
116
|
+
# G06-2: False (legacy) computes VIF on raw values with non-numeric
|
|
117
|
+
# survivors excluded+warned (raw string columns crash statsmodels);
|
|
118
|
+
# True computes VIF on the WOE-encoded INS view (all-numeric, matches
|
|
119
|
+
# the LR design-matrix collinearity semantics).
|
|
120
|
+
vif_use_woe_bins: bool = False
|
|
116
121
|
|
|
117
122
|
|
|
118
123
|
def screen_config_from_mapping(
|
|
@@ -181,6 +186,7 @@ def screen_config_from_mapping(
|
|
|
181
186
|
vif_threshold=float(cfg.get("vif_threshold", 10.0)),
|
|
182
187
|
vif_min_features=int(cfg.get("vif_min_features", 2)),
|
|
183
188
|
vif_tie_break_metric=str(cfg.get("vif_tie_break_metric", "iv")),
|
|
189
|
+
vif_use_woe_bins=bool(cfg.get("vif_use_woe_bins", False)),
|
|
184
190
|
)
|
|
185
191
|
|
|
186
192
|
|
|
@@ -199,6 +205,10 @@ def fit_screening_woe_engine(
|
|
|
199
205
|
from Modeling_Tool.Pipeline._common import apply_woe_fit_query
|
|
200
206
|
|
|
201
207
|
fit_ins, _ = apply_woe_fit_query(train, woe_fit_query, target=target_col)
|
|
208
|
+
# A screening WOE fit is an internal diagnostic artifact. In particular,
|
|
209
|
+
# WOE_Master can append transformed columns while fitting/transforming, so
|
|
210
|
+
# never let an opt-in screen stage mutate the caller's INS frame.
|
|
211
|
+
fit_ins = fit_ins.copy()
|
|
202
212
|
if woe_engine.lower() == "monotone":
|
|
203
213
|
from Modeling_Tool import MonotoneWOEBinner
|
|
204
214
|
|
|
@@ -236,7 +246,12 @@ def fit_screening_woe_engine(
|
|
|
236
246
|
|
|
237
247
|
|
|
238
248
|
def _needs_woe_bins(config: FeatureScreenConfig) -> bool:
|
|
239
|
-
return
|
|
249
|
+
return (
|
|
250
|
+
config.psi_use_woe_bins
|
|
251
|
+
or config.iv_use_woe_bins
|
|
252
|
+
or config.corr_use_woe_bins
|
|
253
|
+
or (config.vif_enabled and config.vif_use_woe_bins)
|
|
254
|
+
)
|
|
240
255
|
|
|
241
256
|
|
|
242
257
|
def _resolve_screening_binner(
|
|
@@ -250,6 +265,22 @@ def _resolve_screening_binner(
|
|
|
250
265
|
return prefit_woe_engine
|
|
251
266
|
if not _needs_woe_bins(config):
|
|
252
267
|
return None
|
|
268
|
+
categorical = [
|
|
269
|
+
col for col in (config.categorical_features or []) if col in feature_cols
|
|
270
|
+
]
|
|
271
|
+
if (
|
|
272
|
+
config.vif_enabled
|
|
273
|
+
and config.vif_use_woe_bins
|
|
274
|
+
and categorical
|
|
275
|
+
and str(config.woe_engine).lower() != "monotone"
|
|
276
|
+
):
|
|
277
|
+
raise ValueError(
|
|
278
|
+
"vif_use_woe_bins=True with categorical_features requires "
|
|
279
|
+
"woe_engine='monotone'. The equal_freq WOE_Master screening "
|
|
280
|
+
"engine does not support categorical fitting on this path; use "
|
|
281
|
+
"the monotone engine or leave vif_use_woe_bins=False to retain "
|
|
282
|
+
"the raw-basis exclude-and-warn behavior."
|
|
283
|
+
)
|
|
253
284
|
return fit_screening_woe_engine(
|
|
254
285
|
splits["ins"],
|
|
255
286
|
feature_cols,
|
|
@@ -393,6 +424,11 @@ def _woe_bins_unweighted_screen(
|
|
|
393
424
|
ins, current, config, selection_evidence, gate_iv_map,
|
|
394
425
|
summary_rows, dropped_rows, stage_tables,
|
|
395
426
|
weight_col=None, on_empty_stage=config.on_empty_stage,
|
|
427
|
+
woe_frame_fn=(
|
|
428
|
+
_vif_woe_frame_fn(ins, binner)
|
|
429
|
+
if config.vif_enabled and config.vif_use_woe_bins
|
|
430
|
+
else None
|
|
431
|
+
),
|
|
396
432
|
)
|
|
397
433
|
|
|
398
434
|
summary_rows.append(_summary_row("final", len(feature_cols), len(current), None, None))
|
|
@@ -427,6 +463,50 @@ def _bins_to_numpy(bins: Any) -> np.ndarray:
|
|
|
427
463
|
return np.asarray(bins, dtype=object)
|
|
428
464
|
|
|
429
465
|
|
|
466
|
+
def _vif_woe_frame_fn(
|
|
467
|
+
ins: pd.DataFrame, binner: Any | None
|
|
468
|
+
) -> Callable[[list[str]], pd.DataFrame] | None:
|
|
469
|
+
"""Lazy WOE-encoded INS view for the VIF gate (G06-2,
|
|
470
|
+
``vif_use_woe_bins=True``). Returns None when no screening engine was
|
|
471
|
+
fitted — the gate raises an actionable error in that case. Columns are
|
|
472
|
+
renamed back to the raw feature names so drop bookkeeping stays on the
|
|
473
|
+
selection's own vocabulary."""
|
|
474
|
+
if binner is None:
|
|
475
|
+
return None
|
|
476
|
+
def _frame(feats: list[str]) -> pd.DataFrame:
|
|
477
|
+
names = list(feats)
|
|
478
|
+
# Construct the adapter only when this opt-in gate actually reaches
|
|
479
|
+
# VIF. This preserves the historical opaque-prefit-engine path when
|
|
480
|
+
# VIF/WOE is disabled and avoids doing work at a min-feature floor.
|
|
481
|
+
from Modeling_Tool.WOE.WOE_Adapter import as_woe_engine
|
|
482
|
+
|
|
483
|
+
engine_suffix = str(getattr(binner, "woe_suffix", "_woe"))
|
|
484
|
+
try:
|
|
485
|
+
adapter = as_woe_engine(binner, woe_suffix=engine_suffix)
|
|
486
|
+
except TypeError as exc:
|
|
487
|
+
raise ValueError(
|
|
488
|
+
"vif_use_woe_bins=True requires a supported fitted WOE "
|
|
489
|
+
"engine (WOE_Master, MonotoneWOEBinner, or WOEEngineAdapter)."
|
|
490
|
+
) from exc
|
|
491
|
+
suffix = adapter.woe_suffix
|
|
492
|
+
# Transform a copy as well: some legacy engines retain or append
|
|
493
|
+
# intermediate WOE columns on the passed frame.
|
|
494
|
+
tx = adapter.transform(ins.copy(), varlist=names, suffix=suffix)
|
|
495
|
+
expected = [f"{name}{suffix}" for name in names]
|
|
496
|
+
missing = [name for name, column in zip(names, expected) if column not in tx.columns]
|
|
497
|
+
if missing:
|
|
498
|
+
raise ValueError(
|
|
499
|
+
"vif_use_woe_bins=True could not produce WOE columns for "
|
|
500
|
+
f"{missing!r}. Refit the screening WOE engine or supply a "
|
|
501
|
+
"prefit engine that covers every surviving feature."
|
|
502
|
+
)
|
|
503
|
+
frame = tx[expected].copy()
|
|
504
|
+
frame.columns = names
|
|
505
|
+
return frame
|
|
506
|
+
|
|
507
|
+
return _frame
|
|
508
|
+
|
|
509
|
+
|
|
430
510
|
def _screen_engine_payload(
|
|
431
511
|
binner: Any | None,
|
|
432
512
|
*,
|
|
@@ -647,6 +727,11 @@ def _weighted_woe_bins_screen(
|
|
|
647
727
|
ins, current, config, selection_evidence, gate_iv_map,
|
|
648
728
|
summary_rows, dropped_rows, stage_tables,
|
|
649
729
|
weight_col=weight_col, on_empty_stage=config.on_empty_stage,
|
|
730
|
+
woe_frame_fn=(
|
|
731
|
+
_vif_woe_frame_fn(ins, binner)
|
|
732
|
+
if config.vif_enabled and config.vif_use_woe_bins
|
|
733
|
+
else None
|
|
734
|
+
),
|
|
650
735
|
)
|
|
651
736
|
|
|
652
737
|
summary_rows.append(_summary_row("final", len(feature_cols), len(current), None, weight_col))
|