SuperModelingFactory 0.5.6__tar.gz → 0.5.8__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.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Parallel_ODPS_Manager.py +23 -2
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Screen.py +11 -1
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Weighted_Screen.py +22 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/feature_validation.py +4 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/field_meta.py +2 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/reject_inference.py +120 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/__init__.py +1 -1
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/PKG-INFO +2 -2
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/README.md +1 -1
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/PKG-INFO +2 -2
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/pyproject.toml +1 -1
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/setup.py +1 -1
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/ExcelMaster/ExcelFormatTool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/ExcelMaster/ExcelMaster.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/ExcelMaster/Template.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/ExcelMaster/Utility.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/ExcelMaster/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/LICENSE +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/MANIFEST.in +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Binning_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Binning_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Check_DuckDB_Compatibility.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Json_Data_Converter.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Model_Registry_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/ODPS_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Parallel_Engine.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Proc_Compare.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Slope_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Slope_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/XOR_Encryptor.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/XOR_Encryptor.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/kDataFrame.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/kDataFrame.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/sample_weight_utils.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/utils.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Evaluation_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Evaluation_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Model_Eval_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Model_Eval_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/evaluate_model.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/evaluate_model.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/weighted_eval_utils.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Explainability/Coalition_Structure.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Explainability/Model_Explainer.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Explainability/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Distribution_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Distribution_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Insights.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Insights.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/PSI_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/PSI_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/WOE_Engine_Feature_Patch.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/Backward_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/Backward_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/GBM_Search_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/GBM_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/GBM_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/LRM_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/LRM_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/_common.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/credit_model.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/mock_sample.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/orchestrator.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/sample_analysis.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/score_comparison.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/score_consistency_uat.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/screening_artifact.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Distribution_Adaptation.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Distribution_Adaptation.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Reject_Infer.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Reject_Infer.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Sample_Split.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Sample_Split.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/UAT/UAT_Consistency_Checker.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/UAT/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Adapter.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Adapter.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Master.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Master.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Monotone_Binner.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Monotone_Binner.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Plot_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Plot_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Report_Builder.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Report_Builder.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/plot_woe_tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/plot_woe_tool.pyi +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/_utils/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/_utils/nan_guard.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/_utils/robust.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/_utils/sentinels.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/KaiTi.ttf +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/WeiRuanYaHei.ttf +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/simsun.ttc +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Report/Report_Tool.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Report/__init__.py +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/SOURCES.txt +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/dependency_links.txt +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/not-zip-safe +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/requires.txt +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/top_level.txt +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/requirements.txt +0 -0
- {supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/setup.cfg +0 -0
|
@@ -64,6 +64,26 @@ def _strip_trailing_semicolon(sql: str) -> str:
|
|
|
64
64
|
return sql.strip().rstrip(";").strip()
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def _first_error_line(exc: BaseException, limit: int = 200) -> str:
|
|
68
|
+
"""Return ``ExcType: first non-empty message line`` for embedding in a
|
|
69
|
+
re-raised error message, truncated to ``limit`` chars.
|
|
70
|
+
|
|
71
|
+
ODPS errors carry the actionable ``ODPS-XXXXXXX: ...`` description on
|
|
72
|
+
their first line followed by long instance/traceback detail; only the
|
|
73
|
+
first line is worth surfacing inline.
|
|
74
|
+
"""
|
|
75
|
+
for line in str(exc).splitlines():
|
|
76
|
+
line = line.strip()
|
|
77
|
+
if line:
|
|
78
|
+
break
|
|
79
|
+
else:
|
|
80
|
+
line = ""
|
|
81
|
+
text = f"{type(exc).__name__}: {line}" if line else type(exc).__name__
|
|
82
|
+
if len(text) > limit:
|
|
83
|
+
return text[:limit] + "..."
|
|
84
|
+
return text
|
|
85
|
+
|
|
86
|
+
|
|
67
87
|
def _pull_one_chunk(
|
|
68
88
|
chunk_spec: dict[str, Any],
|
|
69
89
|
runner: ODPSRunner | None,
|
|
@@ -218,8 +238,9 @@ class ParallelODPSManager:
|
|
|
218
238
|
self.odps_runner.run_sql(probe_sql, to_df=True, n_process=1)
|
|
219
239
|
except Exception as exc:
|
|
220
240
|
raise ValueError(
|
|
221
|
-
f"unique_key validation failed for pull SQL. "
|
|
222
|
-
f"
|
|
241
|
+
f"unique_key validation failed for pull SQL: {_first_error_line(exc)}. "
|
|
242
|
+
f"Common cause: unique_key={self.config.unique_key!r} not visible in "
|
|
243
|
+
f"the SQL scope; see the chained exception for the full ODPS error."
|
|
223
244
|
) from exc
|
|
224
245
|
|
|
225
246
|
def _build_hash_pull_chunks(
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Screen.py
RENAMED
|
@@ -413,7 +413,17 @@ def _weighted_woe_bins_screen(
|
|
|
413
413
|
if var not in ins.columns or ins[var].nunique(dropna=False) <= 1:
|
|
414
414
|
continue
|
|
415
415
|
bins_ins = _bins_to_numpy(adapter.assign_bins(ins, var))
|
|
416
|
-
|
|
416
|
+
x_series = ins[var]
|
|
417
|
+
if pd.api.types.is_numeric_dtype(x_series):
|
|
418
|
+
x_ins = x_series.to_numpy(dtype=float)
|
|
419
|
+
else:
|
|
420
|
+
# Categorical/object feature: IV itself is computed from the
|
|
421
|
+
# already-assigned bins; ``x`` only feeds np.isfinite() inside
|
|
422
|
+
# _weighted_iv_from_assigned_bins to derive the weighted
|
|
423
|
+
# missing rate. A hard float cast crashes on string levels
|
|
424
|
+
# (e.g. '4.高中'), so encode observed -> 1.0 / missing -> NaN,
|
|
425
|
+
# matching the notna semantics of _missing_rate_for_series.
|
|
426
|
+
x_ins = np.where(x_series.notna().to_numpy(), 1.0, np.nan)
|
|
417
427
|
iv_val, n_b, miss = _weighted_iv_from_assigned_bins(y_ins, w_ins, bins_ins, x_ins)
|
|
418
428
|
iv_records.append({
|
|
419
429
|
"var": var,
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Weighted_Screen.py
RENAMED
|
@@ -383,6 +383,28 @@ def _weighted_corr_for_screen(
|
|
|
383
383
|
if cols:
|
|
384
384
|
X = woe_ins[cols].to_numpy(dtype=float)
|
|
385
385
|
return _weighted_pearson_corr_matrix(X, w_ins, nan_policy="pairwise")
|
|
386
|
+
non_numeric = [v for v in current if not pd.api.types.is_numeric_dtype(ins[v])]
|
|
387
|
+
if non_numeric:
|
|
388
|
+
# Raw-value Pearson correlation is undefined for categorical/object
|
|
389
|
+
# features. Exclude them from the correlation computation but keep
|
|
390
|
+
# them in the returned matrix as NaN rows/columns: NaN never exceeds
|
|
391
|
+
# the dedup threshold, so categorical features survive the corr stage
|
|
392
|
+
# untouched instead of crashing the float cast.
|
|
393
|
+
warnings.warn(
|
|
394
|
+
f"raw-value correlation skips {len(non_numeric)} non-numeric "
|
|
395
|
+
f"feature(s) {non_numeric[:5]}; they are kept through the corr "
|
|
396
|
+
f"stage. Set corr_use_woe_bins=True to correlate categorical "
|
|
397
|
+
f"features via their WOE encoding.",
|
|
398
|
+
UserWarning,
|
|
399
|
+
stacklevel=2,
|
|
400
|
+
)
|
|
401
|
+
corr_full = np.full((len(current), len(current)), np.nan)
|
|
402
|
+
numeric_idx = [i for i, v in enumerate(current) if v not in set(non_numeric)]
|
|
403
|
+
if numeric_idx:
|
|
404
|
+
X_num = ins[[current[i] for i in numeric_idx]].astype(float).to_numpy()
|
|
405
|
+
corr_num = _weighted_pearson_corr_matrix(X_num, w_ins, nan_policy=corr_nan_policy)
|
|
406
|
+
corr_full[np.ix_(numeric_idx, numeric_idx)] = corr_num
|
|
407
|
+
return corr_full
|
|
386
408
|
X = ins[current].astype(float).to_numpy()
|
|
387
409
|
return _weighted_pearson_corr_matrix(X, w_ins, nan_policy=corr_nan_policy)
|
|
388
410
|
|
|
@@ -1231,6 +1231,10 @@ class FeatureValidationPipeline:
|
|
|
1231
1231
|
"missing_rate_ref",
|
|
1232
1232
|
cfg.woe_params.get("missing_ref_value", -999999),
|
|
1233
1233
|
),
|
|
1234
|
+
# Without this, a selection run that has to fit its own screening
|
|
1235
|
+
# binner (no prefit WOE engine) would bin declared categorical
|
|
1236
|
+
# features as numeric and crash on string levels.
|
|
1237
|
+
"categorical_features": params.get("categorical_features", cfg.categorical_features),
|
|
1234
1238
|
}
|
|
1235
1239
|
return screen_config_from_mapping(
|
|
1236
1240
|
mapping,
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/field_meta.py
RENAMED
|
@@ -198,6 +198,7 @@ _FIELD_LABELS = {
|
|
|
198
198
|
"train_ri_models": "训练 RI 后模型",
|
|
199
199
|
"ri_model_type": "RI 后模型类型",
|
|
200
200
|
"ri_model_params": "RI 后模型参数",
|
|
201
|
+
"lr_nan_handling": "lr 模型缺失值处理",
|
|
201
202
|
"include_no_ri_benchmark": "加入无 RI benchmark",
|
|
202
203
|
"ri_validation_frac": "RI 验证集比例",
|
|
203
204
|
"write_ri_datasets": "写出 RI 增强样本",
|
|
@@ -352,6 +353,7 @@ _FIELD_OPTIONS = {
|
|
|
352
353
|
"feature_selection_mode": ["run", "from_artifact", "skip"],
|
|
353
354
|
"prescore_model_type": ["lgb", "xgb", "cat", "lr"],
|
|
354
355
|
"ri_model_type": ["lgb", "xgb", "cat", "lr"],
|
|
356
|
+
"lr_nan_handling": ["fillna_median", "fillna_mean", "fillna_0", "raise"],
|
|
355
357
|
"ri_methods": ["simple_augment", "hard_cutoff", "fuzzy_augment", "parceling"],
|
|
356
358
|
"ri_score_direction": ["high_bad", "high_good"],
|
|
357
359
|
"ri_approved_scope": ["reference_only", "output_subset"],
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/reject_inference.py
RENAMED
|
@@ -20,6 +20,48 @@ from ._common import (
|
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
class _LRNanFillWrapper:
|
|
24
|
+
"""Wrap a fitted LRMaster with train-derived NaN/Inf fill values.
|
|
25
|
+
|
|
26
|
+
sklearn's LogisticRegression rejects non-finite inputs while the RI
|
|
27
|
+
pipeline feeds models raw feature frames, so the exact fill values
|
|
28
|
+
learned from the training frame must be re-applied at every predict
|
|
29
|
+
call — otherwise training and scoring would silently run on different
|
|
30
|
+
imputations. Module-level class so saved models stay picklable.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, model: Any, fill_values: dict[str, float], nan_handling: str):
|
|
34
|
+
self._inner = model
|
|
35
|
+
self.fill_values_ = dict(fill_values)
|
|
36
|
+
self.nan_handling = str(nan_handling)
|
|
37
|
+
|
|
38
|
+
def _fill(self, data: pd.DataFrame) -> pd.DataFrame:
|
|
39
|
+
fill_cols = [c for c in self.fill_values_ if c in data.columns]
|
|
40
|
+
if not fill_cols:
|
|
41
|
+
return data
|
|
42
|
+
filled = data.copy()
|
|
43
|
+
block = filled[fill_cols].replace([np.inf, -np.inf], np.nan)
|
|
44
|
+
filled[fill_cols] = block.fillna(self.fill_values_)
|
|
45
|
+
return filled
|
|
46
|
+
|
|
47
|
+
def predict_proba(self, data: pd.DataFrame, varlist: list[str] | None = None, **kwargs: Any) -> Any:
|
|
48
|
+
return self._inner.predict_proba(self._fill(data), varlist=varlist, **kwargs)
|
|
49
|
+
|
|
50
|
+
def predict(self, data: pd.DataFrame, varlist: list[str] | None = None, **kwargs: Any) -> Any:
|
|
51
|
+
return self._inner.predict(self._fill(data), varlist=varlist, **kwargs)
|
|
52
|
+
|
|
53
|
+
def __getattr__(self, name: str) -> Any:
|
|
54
|
+
# Never delegate dunders: leaking the inner model's __getstate__ /
|
|
55
|
+
# __setstate__ into pickle would serialize the wrapper as a bare
|
|
56
|
+
# LRMaster and drop the fill values on reload.
|
|
57
|
+
if name.startswith("__") and name.endswith("__"):
|
|
58
|
+
raise AttributeError(name)
|
|
59
|
+
inner = self.__dict__.get("_inner")
|
|
60
|
+
if inner is None:
|
|
61
|
+
raise AttributeError(name)
|
|
62
|
+
return getattr(inner, name)
|
|
63
|
+
|
|
64
|
+
|
|
23
65
|
@dataclass
|
|
24
66
|
class RejectInferencePipelineConfig:
|
|
25
67
|
output_dir: str = "output/reject_inference"
|
|
@@ -46,6 +88,12 @@ class RejectInferencePipelineConfig:
|
|
|
46
88
|
train_ri_models: bool = True
|
|
47
89
|
ri_model_type: str = "lgb"
|
|
48
90
|
ri_model_params: dict[str, Any] = field(default_factory=dict)
|
|
91
|
+
# NaN/Inf handling for lr models (both prescore_model_type="lr" and
|
|
92
|
+
# ri_model_type="lr"). GBM backends accept NaN natively; sklearn
|
|
93
|
+
# LogisticRegression does not, so lr features are imputed with
|
|
94
|
+
# train-derived fill values that are re-applied at scoring time.
|
|
95
|
+
# "raise" forbids imputation and fails fast on non-finite features.
|
|
96
|
+
lr_nan_handling: Literal["fillna_median", "fillna_mean", "fillna_0", "raise"] = "fillna_median"
|
|
49
97
|
include_no_ri_benchmark: bool = True
|
|
50
98
|
ri_validation_frac: float = 0.2
|
|
51
99
|
save_models: bool = False
|
|
@@ -239,6 +287,9 @@ class RejectInferencePipeline:
|
|
|
239
287
|
if model_type == "lr":
|
|
240
288
|
lr_params = dict(params)
|
|
241
289
|
standardize = bool(lr_params.pop("standardize", False))
|
|
290
|
+
train_fit, val_fit, fill_values = self._prepare_lr_frames(
|
|
291
|
+
train_fit, val_fit, feature_cols,
|
|
292
|
+
)
|
|
242
293
|
model = LRMaster(params=lr_params or None, standardize=standardize)
|
|
243
294
|
model.fit(
|
|
244
295
|
data=train_fit,
|
|
@@ -249,6 +300,8 @@ class RejectInferencePipeline:
|
|
|
249
300
|
val_tgt_name=cfg.target_col,
|
|
250
301
|
weight_col=weight_col,
|
|
251
302
|
)
|
|
303
|
+
if fill_values is not None:
|
|
304
|
+
return _LRNanFillWrapper(model, fill_values, cfg.lr_nan_handling)
|
|
252
305
|
return model
|
|
253
306
|
|
|
254
307
|
model = GradientBoostingModel(model_type, params)
|
|
@@ -264,6 +317,69 @@ class RejectInferencePipeline:
|
|
|
264
317
|
)
|
|
265
318
|
return model
|
|
266
319
|
|
|
320
|
+
def _prepare_lr_frames(
|
|
321
|
+
self,
|
|
322
|
+
train_fit: pd.DataFrame,
|
|
323
|
+
val_fit: pd.DataFrame,
|
|
324
|
+
feature_cols: list[str],
|
|
325
|
+
) -> tuple[pd.DataFrame, pd.DataFrame, dict[str, float] | None]:
|
|
326
|
+
"""Apply cfg.lr_nan_handling to the lr feature frames.
|
|
327
|
+
|
|
328
|
+
GBM backends consume NaN natively; sklearn LogisticRegression raises
|
|
329
|
+
``Input X contains NaN`` on raw pipeline features. Fill values are
|
|
330
|
+
computed on the training frame only and returned so the fitted model
|
|
331
|
+
re-applies the identical imputation at scoring time via
|
|
332
|
+
_LRNanFillWrapper. Callers pass throwaway copies, so frames are
|
|
333
|
+
modified in place.
|
|
334
|
+
"""
|
|
335
|
+
cfg = self.config
|
|
336
|
+
allowed = {"fillna_median", "fillna_mean", "fillna_0", "raise"}
|
|
337
|
+
mode = str(cfg.lr_nan_handling)
|
|
338
|
+
if mode not in allowed:
|
|
339
|
+
raise ValueError(
|
|
340
|
+
f"lr_nan_handling must be one of {sorted(allowed)}; got {mode!r}"
|
|
341
|
+
)
|
|
342
|
+
train_block = train_fit[feature_cols].replace([np.inf, -np.inf], np.nan)
|
|
343
|
+
val_block = val_fit[feature_cols].replace([np.inf, -np.inf], np.nan)
|
|
344
|
+
n_bad_train = int(train_block.isna().sum().sum())
|
|
345
|
+
n_bad_val = int(val_block.isna().sum().sum())
|
|
346
|
+
if mode == "raise":
|
|
347
|
+
if n_bad_train or n_bad_val:
|
|
348
|
+
bad_cols = sorted(
|
|
349
|
+
set(train_block.columns[train_block.isna().any()])
|
|
350
|
+
| set(val_block.columns[val_block.isna().any()])
|
|
351
|
+
)
|
|
352
|
+
raise ValueError(
|
|
353
|
+
f"lr model features contain {n_bad_train + n_bad_val} "
|
|
354
|
+
f"non-finite value(s) across {len(bad_cols)} feature(s) "
|
|
355
|
+
f"(e.g. {bad_cols[:5]}) and lr_nan_handling='raise'. "
|
|
356
|
+
f"Clean the features first, or set lr_nan_handling to "
|
|
357
|
+
f"'fillna_median'/'fillna_mean'/'fillna_0'."
|
|
358
|
+
)
|
|
359
|
+
return train_fit, val_fit, None
|
|
360
|
+
if mode == "fillna_0":
|
|
361
|
+
fill_series = pd.Series(0.0, index=feature_cols)
|
|
362
|
+
elif mode == "fillna_mean":
|
|
363
|
+
fill_series = train_block.mean(numeric_only=True).reindex(feature_cols).fillna(0.0)
|
|
364
|
+
else:
|
|
365
|
+
fill_series = train_block.median(numeric_only=True).reindex(feature_cols).fillna(0.0)
|
|
366
|
+
fill_values = {str(col): float(fill_series[col]) for col in feature_cols}
|
|
367
|
+
if n_bad_train or n_bad_val:
|
|
368
|
+
n_cols = int((train_block.isna().any() | val_block.isna().any()).sum())
|
|
369
|
+
warnings.warn(
|
|
370
|
+
f"lr model: {n_bad_train + n_bad_val} non-finite feature "
|
|
371
|
+
f"value(s) across {n_cols}/{len(feature_cols)} feature(s) "
|
|
372
|
+
f"filled with train-derived {mode} values (sklearn LR cannot "
|
|
373
|
+
f"handle NaN). Fill values are stored on the model and "
|
|
374
|
+
f"re-applied at scoring time; set lr_nan_handling='raise' to "
|
|
375
|
+
f"forbid imputation.",
|
|
376
|
+
UserWarning,
|
|
377
|
+
stacklevel=2,
|
|
378
|
+
)
|
|
379
|
+
train_fit[feature_cols] = train_block.fillna(fill_values)
|
|
380
|
+
val_fit[feature_cols] = val_block.fillna(fill_values)
|
|
381
|
+
return train_fit, val_fit, fill_values
|
|
382
|
+
|
|
267
383
|
def run(self, data: pd.DataFrame) -> RejectInferencePipelineResult:
|
|
268
384
|
cfg = self.config
|
|
269
385
|
feature_cols = self._resolve_feature_cols(data)
|
|
@@ -1074,6 +1190,10 @@ class RejectInferencePipeline:
|
|
|
1074
1190
|
"model_type": model_type,
|
|
1075
1191
|
"random_state": cfg.random_state,
|
|
1076
1192
|
}
|
|
1193
|
+
fill_values = getattr(model, "fill_values_", None)
|
|
1194
|
+
if fill_values is not None:
|
|
1195
|
+
metadata["lr_nan_handling"] = getattr(model, "nan_handling", None)
|
|
1196
|
+
metadata["lr_fill_values"] = dict(fill_values)
|
|
1077
1197
|
save_model(
|
|
1078
1198
|
model,
|
|
1079
1199
|
path,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SuperModelingFactory
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: Credit risk modeling factory: WOE binning, scorecards, LightGBM, Excel reporting.
|
|
5
5
|
Home-page: https://github.com/Kyle-J-Sun/SuperModelingFactory
|
|
6
6
|
Author: Kyle Sun
|
|
@@ -265,7 +265,7 @@ em.close_workbook()
|
|
|
265
265
|
|
|
266
266
|
## 版本
|
|
267
267
|
|
|
268
|
-
- **Version**: 0.5.
|
|
268
|
+
- **Version**: 0.5.8
|
|
269
269
|
- **Author**: Jingkai Sun
|
|
270
270
|
|
|
271
271
|
## 许可证
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SuperModelingFactory
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.8
|
|
4
4
|
Summary: Credit risk modeling factory: WOE binning, scorecards, LightGBM, Excel reporting.
|
|
5
5
|
Home-page: https://github.com/Kyle-J-Sun/SuperModelingFactory
|
|
6
6
|
Author: Kyle Sun
|
|
@@ -265,7 +265,7 @@ em.close_workbook()
|
|
|
265
265
|
|
|
266
266
|
## 版本
|
|
267
267
|
|
|
268
|
-
- **Version**: 0.5.
|
|
268
|
+
- **Version**: 0.5.8
|
|
269
269
|
- **Author**: Jingkai Sun
|
|
270
270
|
|
|
271
271
|
## 许可证
|
|
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
|
|
|
12
12
|
|
|
13
13
|
[project]
|
|
14
14
|
name = "SuperModelingFactory"
|
|
15
|
-
version = "0.5.
|
|
15
|
+
version = "0.5.8"
|
|
16
16
|
description = "Credit risk modeling factory: WOE binning, scorecards, LightGBM, Excel reporting."
|
|
17
17
|
readme = "README.md"
|
|
18
18
|
requires-python = ">=3.10"
|
|
@@ -15,7 +15,7 @@ def _read(path: str) -> str:
|
|
|
15
15
|
|
|
16
16
|
setup(
|
|
17
17
|
name="SuperModelingFactory",
|
|
18
|
-
version=os.environ.get("SMF_VERSION", "0.5.
|
|
18
|
+
version=os.environ.get("SMF_VERSION", "0.5.8"),
|
|
19
19
|
description="Credit risk modeling factory: WOE binning, scorecards, LightGBM, Excel reporting.",
|
|
20
20
|
long_description=_read("README.md"),
|
|
21
21
|
long_description_content_type="text/markdown",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Binning_Tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Binning_Tool.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Json_Data_Converter.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Model_Registry_Tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Parallel_Engine.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/Proc_Compare.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/XOR_Encryptor.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/XOR_Encryptor.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Core/sample_weight_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Evaluation_Tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Evaluation_Tool.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Model_Eval_Tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/Model_Eval_Tool.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/evaluate_model.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/evaluate_model.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Eval/weighted_eval_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Explainability/__init__.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Distribution_Tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Insights.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/Feature_Insights.pyi
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Feature/PSI_Tool.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/Backward_Tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/Backward_Tool.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Model/GBM_Search_Tool.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/credit_model.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/mock_sample.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/orchestrator.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/sample_analysis.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Pipeline/score_comparison.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Reject_Infer.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Reject_Infer.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Sample_Split.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/Sample/Sample_Split.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Monotone_Binner.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Monotone_Binner.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Plot_Tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Plot_Tool.pyi
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Report_Builder.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/WOE_Report_Builder.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/plot_woe_tool.py
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/WOE/plot_woe_tool.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/WeiRuanYaHei.ttf
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/Modeling_Tool/ref_font/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{supermodelingfactory-0.5.6 → supermodelingfactory-0.5.8}/SuperModelingFactory.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|