8000 Fix ElasticNet l1 ratio fails for float-only arrays (#31107) · scikit-learn/scikit-learn@bdef5aa · GitHub
[go: up one dir, main page]

Skip to content

Commit bdef5aa

Browse files
Fix ElasticNet l1 ratio fails for float-only arrays (#31107)
Co-authored-by: Jérémie du Boisberranger <jeremie@probabl.ai>
1 parent 81bb708 commit bdef5aa

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- :class:`feature_selection.SelectFromModel` now correctly works when the estimator
2+
is an instance of :class:`linear_model.ElasticNetCV` with its `l1_ratio` parameter
3+
being an array-like.
4+
By :user:`Vasco Pereira <vasco-s-pereira>`.

sklearn/feature_selection/_from_model.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,18 @@ def _calculate_threshold(estimator, importances, threshold):
3535
est_name = estimator.__class__.__name__
3636
is_l1_penalized = hasattr(estimator, "penalty") and estimator.penalty == "l1"
3737
is_lasso = "Lasso" in est_name
38-
is_elasticnet_l1_penalized = "ElasticNet" in est_name and (
39-
(hasattr(estimator, "l1_ratio_") and np.isclose(estimator.l1_ratio_, 1.0))
40-
or (hasattr(estimator, "l1_ratio") and np.isclose(estimator.l1_ratio, 1.0))
38+
is_elasticnet_l1_penalized = est_name == "ElasticNet" and (
39+
hasattr(estimator, "l1_ratio") and np.isclose(estimator.l1_ratio, 1.0)
4140
)
42-
if is_l1_penalized or is_lasso or is_elasticnet_l1_penalized:
41+
is_elasticnetcv_l1_penalized = est_name == "ElasticNetCV" and (
42+
hasattr(estimator, "l1_ratio_") and np.isclose(estimator.l1_ratio_, 1.0)
43+
)
44+
if (
45+
is_l1_penalized
46+
or is_lasso
47+
or is_elasticnet_l1_penalized
48+
or is_elasticnetcv_l1_penalized
49+
):
4350
# the natural default threshold is 0 when l1 penalty was used
4451
threshold = 1e-5
4552
else:

sklearn/feature_selection/tests/test_from_model.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from sklearn import datasets
99
from sklearn.base import BaseEstimator
1010
f 8000 rom sklearn.cross_decomposition import CCA, PLSCanonical, PLSRegression
11-
from sklearn.datasets import make_friedman1
11+
from sklearn.datasets import make_friedman1, make_regression
1212
from sklearn.decomposition import PCA
1313
from sklearn.ensemble import HistGradientBoostingClassifier, RandomForestClassifier
1414
from sklearn.exceptions import NotFittedError
@@ -489,6 +489,21 @@ def test_prefit_max_features():
489489
model.transform(data)
490490

491491

492+
def test_get_feature_names_out_elasticnetcv():
493+
"""Check if ElasticNetCV works with a list of floats.
494+
495+
Non-regression test for #30936."""
496+
X, y = make_regression(n_features=5, n_informative=3, random_state=0)
497+
estimator = ElasticNetCV(l1_ratio=[0.25, 0.5, 0.75], random_state=0)
498+
selector = SelectFromModel(estimator=estimator)
499+
selector.fit(X, y)
500+
501+
names_out = selector.get_feature_names_out()
502+
mask = selector.get_support()
503+
expected = np.array([f"x{i}" for i in range(X.shape[1])])[mask]
504+
assert_array_equal(names_out, expected)
505+
506+
492507
def test_prefit_get_feature_names_out():
493508
"""Check the interaction between prefit and the feature names."""
494509
clf = RandomForestClassifier(n_estimators=2, random_state=0)

0 commit comments

Comments
 (0)
0