Fix importance-based feature subsampling never sharing pools across estimators - #1141
Open
LeoGrin wants to merge 2 commits into
Open
Fix importance-based feature subsampling never sharing pools across estimators#1141LeoGrin wants to merge 2 commits into
LeoGrin wants to merge 2 commits into
Conversation
…stimators _collect_importance_orderings expanded its orderings to one entry per estimator, so the position-keyed pools in _subsample_features_importance_based were always private and the documented round-robin coverage of non-top-K features never engaged: every draw was an independent random sample, leaving some features unseen by any estimator even when the combined budget covered them all. Return only the unique orderings; the consumer's cycling assigns them to estimators unchanged, and estimators sharing an ordering now share its pool. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bejaeger
requested changes
Jul 29, 2026
bejaeger
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for fixing. IIUC this fixes one issue but not the other one where n_samples is large (the case for "auto" running the gini_importance method). See comment
Should we kill two birds with one stone and also this path here?
| @@ -960,7 +961,7 @@ def _collect_importance_orderings( | |||
| random_state=int(rng.integers(0, np.iinfo(np.int32).max)), | |||
| ) | |||
| orderings.append(fit_ordering_fn(X[idx], y[idx])) | |||
Collaborator
There was a problem hiding this comment.
So if we're dealing with more samples than max_samples (which has 100k as default), we'd still get separate orderings per estimator it seems and the issue that's tackled here remains IIUC?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Didn't check performance on actual datasets with this change, but can look into it if we're not confident in the fix!
Summary
With
FEATURE_SUBSAMPLING_METHOD="gini_feature_importance"(or"auto"on >100k-sample datasets needing subsampling), each estimator keeps the top-K most important features and fills the rest of its budget from the remaining features. Since #913 that fill is documented — and unit-tested — as balanced round-robin from a pool shared by estimators using the same importance ordering, guaranteeing every feature lands in at least one estimator when the combined budget allows.That sharing never happened in production.
_collect_importance_orderingsexpanded its result to one entry per estimator ([ordering] * n_estimators, or cyclic expansion of the subsample orderings), so in_subsample_features_importance_basedthe position-keyed pools (ordering_idx = i % n_orderingswithn_orderings == n_estimators) were always private and initially empty: every draw degenerated to an independent uniform sample — the pre-#913 behavior. The unit tests passed because they feed short orderings lists (1–2 entries for many estimators), a shape the production caller never produces.Measured on the minimal case (12 features, top-4, budget 8, 2 estimators — combined budget exactly covers the tail): the production shape misses at least one feature in 20/20 seeds; the fixed shape covers all features in 20/20. At production scale the auto-scaler raises
n_estimatorsto the exact minimum where round-robin would barely cover everything — the point where independent sampling misses the most (~30–50% of non-top features), directly contradicting the scaler's "every feature is included in at least one ensemble member" warning.Fix
_collect_importance_orderingsnow returns only the unique orderings (one for small datasets, up ton_subsamplesfor large). The consumer's existingi % n_orderingscycling assigns orderings to estimators identically to the old expansion, so the estimator→ordering mapping is unchanged — the only behavioral difference is that estimators sharing an ordering now genuinely share its pool, which is what #913's docstrings, comments, and tests already describe.Not addressed here (separate issue):
scale_n_estimators_for_feature_coveragecomputes the required estimator count from the raw budget, ignoring that the importance method re-includes top-K in every member; it can under-provision for gini even with this fix.Behavior impact
Results change (deterministically, given a seed) only for fits where the gini path is active:
FEATURE_SUBSAMPLING_METHOD="gini_feature_importance", or"auto"with >100k training samples and more features thanmax_features_per_estimator. All other configurations are unaffected.Tests
_collect_importance_orderingsfed to_subsample_features_importance_basedmust cover all features across 20 seeds when the combined budget suffices (fails 20/20 on main)._collect_importance_orderingssmall-data shape test.min(n_estimators, n_samples // max_samples + 1)distinct orderings.🤖 Generated with Claude Code