v0.9.3¶
0.9.2 made the screening IV on WOE bins leave class-pure bins out of the sum (screen_iv_convention="guarded"). A
near-perfect separator then reports an ordinary-looking iv (13.8 drops to 1.8 on the leak frame of the tests), and the
only remaining guard, iv_upper_threshold, was off by default, so such a leak passed the screening without any sign.
0.9.3 closes that gap with a leak warning and a default upper limit, makes sure that no empty-stage fallback brings a
dropped leak back, and warns about every leak the limit drops. Scoring does not change. The
upgrade guide explains how to keep the selections of 0.9.2.
Behavior changes (exception to RELEASING.md)
A patch release normally changes no numbers on healthy inputs. 0.9.3 changes which features the screening keeps, because 0.9.2 let leaks through silently; this is a documented exception to the release policy, as in 0.9.1 and 0.9.2.
| Change | What changes | Keep the 0.9.2 selections with |
|---|---|---|
(a) iv_upper_threshold defaults to 2.0 (was None) in FeatureScreenConfig, screen_config_from_mapping, weighted_feature_screen, the selection of FeatureValidationPipeline and the feature_selection of CreditModelPipeline; on WOE bins under the guarded convention the limit gates on iv_raw (the larger of iv_raw and the zero-cell-floored IV), never on the guarded iv (section 2) |
Features whose floored IV or iv_raw is above 2.0 are dropped (dropped_detail reason iv_above_upper, or iv_above_upper_sv_pure when the excess comes from class-pure special-value bins). This also applies to the default screening of CreditModelPipeline without WOE bins |
iv_upper_threshold=None, or your previous explicit value (see the migration note) |
(b) New leak warning and iv_gap_flag column (section 1) |
A UserWarning per feature whose iv_raw is far above iv, and the boolean column iv_gap_flag in iv_table and the iv tables of the selection summaries. It never drops a feature |
Nothing to restore (no number changes); filter the warning or set iv_gap_ratio_warn / iv_gap_abs_warn to inf |
| (c) The empty-stage fallback no longer revives leak-gate drops (section 3) | Under the default on_empty_stage="keep_all_warn", a stage that would drop every feature never brings back a feature that the upper limit dropped; from the IV stage on it keeps only the fallback_top_k (5) other features with the highest screening IV (marked fallback_kept in dropped_detail, with a warning), and it raises EmptyStageError when only leak-gate drops are left. Before, it kept every feature, so with the limit on the selection could hold MORE features than without it |
on_empty_stage="keep_all" (the old fallback, leak drops included; for comparisons with old results only) |
| (d) A warning for every leak-gate drop (section 4) | A UserWarning per feature that iv_upper_threshold drops ("possible target leakage; check the field's time point (PIT) and source before training"), on every screening path, next to the gap warning of (b) when both apply |
Nothing to restore (no number changes); filter the warning or switch the limit off |
1. Leak Warning and iv_gap_flag¶
Every screening path that reports both iv and iv_raw (feature_screen, feature_screen_from_dataframe,
weighted_feature_screen, the selection of FeatureValidationPipeline and the screening of CreditModelPipeline on WOE
bins) now checks each feature:
with iv_gap_ratio_warn=2.0 and iv_gap_abs_warn=0.5 by default (new fields of FeatureScreenConfig, also keys of the
pipelines' selection_params / feature_selection and arguments of weighted_feature_screen). An iv at or below
1e-12 counts as zero, and then only the difference rule applies. A matching feature gets iv_gap_flag=True in
iv_table and a UserWarning that names it:
f_leak: iv=1.8116, iv_raw=13.7705, iv_sv_pure=11.9589, n_sv_pure=1500 (iv_raw / iv >= 2 or iv_raw - iv >= 0.5):
possible leakage or unresolved class-pure bins; review before training
The rule only warns and flags; it never drops a feature. The flag is set from the rule alone, also for a feature that
the upper limit drops, so the screening report shows both the drop reason (dropped_detail) and the flag (iv_table).
CreditModelPipeline now also puts dropped_detail into feature_selection_summary (and feature_selection_dropped.csv).
Under screen_iv_convention="raw", and on the paths without WOE bins, iv equals iv_raw, so nothing is flagged.
2. The Upper Limit Is On by Default and Gates on iv_raw¶
iv_upper_threshold defaults to 2.0; iv_upper_threshold=None switches it off (a dict key set to None does too; a
missing key takes the default). The value the limit tests:
| Path | Tested value |
|---|---|
WOE bins, screen_iv_convention="guarded" (the default) |
The larger of iv_raw (every WOE bin counted) and the zero-cell-floored IV on equal-frequency bins; iv_raw alone where the floored IV cannot be computed (non-numeric features). Never the guarded iv |
WOE bins, screen_iv_convention="raw" |
As in 0.9.2: the floored IV on equal-frequency bins, iv_raw where it cannot be computed |
| No WOE bins | As in 0.9.2: the floored IV, the reported IV where it cannot be computed |
The floored IV keeps catching a near-perfect separator that the binner's merge folded into one ordinary bin (0.9.1);
iv_raw catches a class-pure WOE bin that equal-frequency bins mix with other values. dropped_detail records which
one decided (metric iv_floored or iv_raw) and keeps the 0.9.2 reasons: iv_above_upper, or
iv_above_upper_sv_pure when the feature would not exceed the limit without its class-pure special-value bins.
Before and after¶
| Frame | 0.9.2 defaults | 0.9.3 defaults |
|---|---|---|
Leak frame, f_leak (y * 3 + noise) |
iv 1.8116, iv_raw 13.7705: kept, no warning |
Same IVs; iv_gap_flag True, warning; dropped (iv_above_upper, floored IV 21.30) |
Leak frame, f_sv (12% of rows on an all-bad special value) |
iv 0.4617, iv_raw 6.1464: kept |
Flagged, warning; dropped (iv_above_upper_sv_pure) |
Special value hidden in an equal-frequency bin (x_sv, 6% all-bad) |
iv 0.10, iv_raw 2.83, floored IV below 2.0: kept, also with an explicit iv_upper_threshold=2.0 |
Flagged, warning; dropped (metric=iv_raw, iv_above_upper_sv_pure) |
-999 example (150 all-good rows on -999) |
iv 1.3609, iv_raw 1.7407, iv_sv_pure 0.3797, n_sv_pure 150: kept |
Identical numbers; tested value 1.7407 < 2.0: kept; ratio 1.28 and difference 0.38: not flagged, no gap warning and no leak warning |
x (leak, iv = iv_raw far above 2.0) + z (noise, iv 0.0020 below 0.02), selected_features |
['x'] (no limit) |
First 0.9.3 commit (7e601de): ['x', 'z'] (both dropped, the fallback revived both). Now: ['z']; x stays dropped (iv_above_upper, leak warning), z is fallback_kept with the warning IV stage empty; fallback kept z (iv=0.0020); .... on_empty_stage="keep_all": ['x', 'z']; iv_upper_threshold=None: ['x'] |
x alone, selected_features |
['x'] (no limit) |
7e601de: ['x'] (revived). Now: EmptyStageError naming x (iv_above_upper), after the leak warning. on_empty_stage="keep_all": ['x'] |
The binning is unchanged: the -999 bin keeps its WOE of -10.4963 (IV 0.3797, ordinary bins 1.3609), and apply_woe
gives it -10.4963.
3. The Empty-Stage Fallback Never Revives a Leak¶
A stage that would drop every feature used to keep all of them (on_empty_stage="keep_all_warn"). With the upper limit
on, a leak x dropped by the limit and a noise feature z dropped by the lower limit emptied the IV stage, and the
fallback brought both back: the selection was ['x', 'z'] with the limit and ['x'] without it. Since this release:
- Hard drops are never revived. A feature that the leak gate dropped (
dropped_detailreasoniv_above_upperoriv_above_upper_sv_pure, the setHARD_DROP_REASONSofModeling_Tool.Feature.Weighted_Screen) is a hard drop. No fallback brings it back: not the IV stage, not the VIF, group-stability or multi-target gate, not the CSV batch mode ofFeatureValidationPipeline(its first pass keeps every candidate of an empty stage, but the leak drops among them never reach the global pass), and not the backward elimination ofCreditModelPipeline, which falls back to the screened features only. When the screening ofCreditModelPipelinefails for another reason after the IV stage (for example a G03 setting without evidence), every feature is kept except the leak drops found before the failure, listed infeature_selection_summary["hard_dropped"]. The correlation stage never empties (it keeps one feature of each correlated group). - The fallback keeps only the best soft drops. From the IV stage on, an empty stage keeps the
fallback_top_k(new field ofFeatureScreenConfig, default 5; also a key offeature_selection/selection_paramsand an argument ofweighted_feature_screen) features with the highest screening IV, theivcolumn that the threshold tested (guarded by default), in that order. It never ranks byiv_raw, which would favour features with large class-pure special-value bins. It warns, for exampleIV stage empty; fallback kept z (iv=0.0008); review the data before training, and marks the kept features indropped_detailwith the reasonfallback_kept: on their own row of the stage (the reason is replaced; the metric, value and threshold stay and show the cause), or on a new row withmetric="iv", their IV and the stage threshold. The<stage>_fallbackrow ofsummarygives the number kept inn_out. The missing-rate and PSI stages run before any IV exists and before the leak gate: their fallback keeps every feature, as before. - Only hard drops left: the screening stops. When every feature that an empty stage would drop is a hard drop, it
raises
EmptyStageError(the existingValueErrorsubclass) with the feature names and reasons, for example... every one of them was dropped by the leak gate, which no fallback may revive: x (iv_above_upper). The leak warning of each feature (section 4) is issued before the raise; it is not part of the message.CreditModelPipelinedoes not catch the error, and a CSV batch run whose candidates are all leak drops raises it as well. - The old fallback stays available.
on_empty_stage="keep_all"(new value) keeps every feature, hard drops included, exactly as before this release. It can let a leak back in: use it only to compare with old results.on_empty_stage="raise"raises as before, and"keep_all_warn"keeps its name for compatibility.
4. A Warning for Every Leak-Gate Drop¶
A plain leak whose guarded iv and iv_raw are both far above 2.0 was dropped (iv_above_upper) without any warning:
only the gap of section 1 warned, and it needs class-pure bins. Every feature that iv_upper_threshold drops now gets
one UserWarning, on every screening path (unweighted and weighted, with and without WOE bins, and in both pipelines):
x: dropped by the IV upper limit (iv_above_upper): iv_floored=9.2127 > iv_upper_threshold=2 (iv=2.5592,
iv_sv_pure=nan, n_sv_pure=nan): possible target leakage; check the field's time point (PIT) and source before training
It names the value the limit tested (iv_floored or iv_raw, as metric in dropped_detail), the threshold, iv,
iv_sv_pure and n_sv_pure (nan on the paths without WOE bins). A feature that also trips the gap rule gets both
warnings, because the two point to different checks: the leak warning says the IV is above the upper limit (check the
field's time point and source), the gap warning says the guarded and the raw IV are far apart (check for unresolved
class-pure bins).
5. weighted_feature_screen Exposes the Convention and the Leak Settings¶
weighted_feature_screen gains screen_iv_convention (default "guarded"), iv_upper_threshold (default 2.0, not
exposed before), iv_gap_ratio_warn and iv_gap_abs_warn, appended after the existing arguments and passed on to
FeatureScreenConfig exactly as feature_screen uses them, and fallback_top_k (default 5) with the new
on_empty_stage="keep_all" (section 3). With screen_iv_convention="raw" its IV numbers are those of 0.9.1 (tested on
the -999 frame: 1.79 unweighted, 1.768988838079573 weighted).
6. Documentation Build¶
requirements-docs.txt of the documentation repository pins mkdocs<2 (MkDocs 2.0 removes the plugin and theme
systems the site uses) and keeps pymdown-extensions<12.2 until mkdocstrings supports 12.2.
7. Code Cleanup¶
No behavior change: the unused imports weighted_rate (Feature/Weighted_Screen.py) and var_corr_filter
(Feature/WOE_Engine_Feature_Patch.py) are removed, and the Iterable annotation of feature_validation.py is imported
from collections.abc.
Out of Scope¶
Unchanged on purpose: the WOE of class-pure bins and the scoring (no WOE cap, no automatic "neutral"), the default
sv_woe_smoothing="none", the IV thresholds and the gap-warning thresholds, the guarded and raw conventions, the default
engine of CreditModelPipeline (equal_freq, which screens without WOE bins), and the first two known issues of 0.9.0.
The third one (a stricter threshold can return a looser selection) is narrowed by section 3: from the IV stage on the
fallback keeps at most fallback_top_k features and never a leak drop; the missing-rate and PSI stages still keep every
feature.
Tests¶
test_leak_gate_defaults.py (new, 39 tests): the defaults, the gap rule, the leak frame (flag, warning, drop, both
paths), the limit on iv_raw (the hidden special value), the -999 frame (exact numbers, no drop, no warning),
iv_upper_threshold=None against numbers recorded with 0.9.2, weighted_feature_screen with "raw" against numbers
recorded with 0.9.1, and both pipelines. Existing tests that describe the screening without an upper limit pass
iv_upper_threshold=None explicitly; their assertions are unchanged.
test_empty_stage_fallback.py (new, 44 tests): the settings and their validation; the x + z frame on all four
screening paths (['z'], x with iv_above_upper, z with fallback_kept, both warnings), with keep_all
(['x', 'z']), without the limit (['x']) and with "raise"; x alone (EmptyStageError, warning before the raise);
the top 5 of eight soft drops by iv, in order, on a frame where iv_raw would rank differently; an empty
group-stability gate of FeatureValidationPipeline, an empty backward elimination and a failed screening of
CreditModelPipeline, and the CSV batch mode; one leak warning per leak-gate drop and both warnings for a class-pure leak;
the results of 7e601de where the fallback does not run (recorded numbers on all four paths) and the -999 frame.
Nine tests whose synthetic features are near-separators above the limit passed only because the old fallback revived
them; they now pass iv_upper_threshold=None (their assertions are unchanged). Two tests of the old fallback now check
the new one: the pipeline test of the default fallback expects the top-k warning and the fallback_kept rows, and the
group-stability test of insufficient_group_policy="drop" expects the rescued rows as fallback_kept with their
original metric (eligible_groups) and threshold (the original reason stays under on_empty_stage="keep_all").