8000
We read every piece of feedback, and take your input very seriously.
1 parent 81bb708 commit bdef5aaCopy full SHA for bdef5aa
doc/whats_new/upcoming_changes/sklearn.feature_selection/31107.fix.rst
@@ -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
@@ -35,11 +35,18 @@ def _calculate_threshold(estimator, importances, threshold):
35
est_name = estimator.__class__.__name__
36
is_l1_penalized = hasattr(estimator, "penalty") and estimator.penalty == "l1"
37
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))
+ is_elasticnet_l1_penalized = est_name == "ElasticNet" and (
+ hasattr(estimator, "l1_ratio") and np.isclose(estimator.l1_ratio, 1.0)
41
)
42
- if is_l1_penalized or is_lasso or is_elasticnet_l1_penalized:
+ is_elasticnetcv_l1_penalized = est_name == "ElasticNetCV" and (
+ 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
+ ):
50
# the natural default threshold is 0 when l1 penalty was used
51
threshold = 1e-5
52
else:
sklearn/feature_selection/tests/test_from_model.py
@@ -8,7 +8,7 @@
8
from sklearn import datasets
9
from sklearn.base import BaseEstimator
10
from sklearn.cross_decomposition import CCA, PLSCanonical, PLSRegression
11
-from sklearn.datasets import make_friedman1
+from sklearn.datasets import make_friedman1, make_regression
12
from sklearn.decomposition import PCA
13
from sklearn.ensemble import HistGradientBoostingClassifier, RandomForestClassifier
14
from sklearn.exceptions import NotFittedError
@@ -489,6 +489,21 @@ def test_prefit_max_features():
489
model.transform(data)
490
491
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
507
def test_prefit_get_feature_names_out():
508
"""Check the interaction between prefit and the feature names."""
509
clf = RandomForestClassifier(n_estimators=2, random_state=0)