Skip to content

Commit 0dfc9a5

Browse files
erikcsagramfort
authored andcommitted
[MRG + 1] ElasticNetCV: raise ValueError if l1_ratio=0 (scikit-learn#7591)
Raise ValueError if l1_ratio=0 in ElasticNetCV and alphas=None
1 parent 5adc832 commit 0dfc9a5

File tree

3 files changed

+60
-16
lines changed

3 files changed

+60
-16
lines changed

sklearn/linear_model/coordinate_descent.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ def _alpha_grid(X, y, Xy=None, l1_ratio=1.0, fit_intercept=True,
4949
Xy = np.dot(X.T, y) that can be precomputed.
5050
5151
l1_ratio : float
52-
The elastic net mixing parameter, with ``0 <= l1_ratio <= 1``.
53-
For ``l1_ratio = 0`` the penalty is an L2 penalty. ``For
54-
l1_ratio = 1`` it is an L1 penalty. For ``0 < l1_ratio <
55-
1``, the penalty is a combination of L1 and L2.
52+
The elastic net mixing parameter, with ``0 < l1_ratio <= 1``.
53+
For ``l1_ratio = 0`` the penalty is an L2 penalty. (currently not
54+
supported) ``For l1_ratio = 1`` it is an L1 penalty. For
55+
``0 < l1_ratio <1``, the penalty is a combination of L1 and L2.
5656
5757
eps : float, optional
5858
Length of the path. ``eps=1e-3`` means that
@@ -77,6 +77,11 @@ def _alpha_grid(X, y, Xy=None, l1_ratio=1.0, fit_intercept=True,
7777
copy_X : boolean, optional, default True
7878
If ``True``, X will be copied; else, it may be overwritten.
7979
"""
80+
if l1_ratio == 0:
81+
raise ValueError("Automatic alpha grid generation is not supported for"
82+
" l1_ratio=0. Please supply a grid by providing "
83+
"your estimator with the appropriate `alphas=` "
84+
"argument.")
8085
n_samples = len(y)
8186

8287
sparse_center = False

sklearn/linear_model/tests/test_coordinate_descent.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from sklearn.utils.testing import assert_greater
1818
from sklearn.utils.testing import assert_raises
1919
from sklearn.utils.testing import assert_raises_regex
20+
from sklearn.utils.testing import assert_raise_message
2021
from sklearn.utils.testing import assert_warns
2122
from sklearn.utils.testing import assert_warns_message
2223
from sklearn.utils.testing import ignore_warnings
@@ -712,3 +713,35 @@ def test_enet_float_precision():
712713
assert_array_almost_equal(intercept[np.float32],
713714
intercept[np.float64],
714715
decimal=4)
716+
717+
718+
def test_enet_l1_ratio():
719+
# Test that an error message is raised if an estimator that
720+
# uses _alpha_grid is called with l1_ratio=0
721+
msg = ("Automatic alpha grid generation is not supported for l1_ratio=0. "
722+
"Please supply a grid by providing your estimator with the "
723+
"appropriate `alphas=` argument.")
724+
X = np.array([[1, 2, 4, 5, 8], [3, 5, 7, 7, 8]]).T
725+
y = np.array([12, 10, 11, 21, 5])
726+
727+
assert_raise_message(ValueError, msg, ElasticNetCV(
728+
l1_ratio=0, random_state=42).fit, X, y)
729+
assert_raise_message(ValueError, msg, MultiTaskElasticNetCV(
730+
l1_ratio=0, random_state=42).fit, X, y[:, None])
731+
732+
# Test that l1_ratio=0 is allowed if we supply a grid manually
733+
alphas = [0.1, 10]
734+
estkwds = {'alphas': alphas, 'random_state': 42}
735+
est_desired = ElasticNetCV(l1_ratio=0.00001, **estkwds)
736+
est = ElasticNetCV(l1_ratio=0, **estkwds)
737+
with ignore_warnings():
738+
est_desired.fit(X, y)
739+
est.fit(X, y)
740+
assert_array_almost_equal(est.coef_, est_desired.coef_, decimal=5)
741+
742+
est_desired = MultiTaskElasticNetCV(l1_ratio=0.00001, **estkwds)
743+
est = MultiTaskElasticNetCV(l1_ratio=0, **estkwds)
744+
with ignore_warnings():
745+
est.fit(X, y[:, None])
746+
est_desired.fit(X, y[:, None])
747+
assert_array_almost_equal(est.coef_, est_desired.coef_, decimal=5)

sklearn/linear_model/tests/test_logistic.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -588,24 +588,28 @@ def test_logistic_regression_sample_weights():
588588
# Test that passing sample_weight as ones is the same as
589589
# not passing them at all (default None)
590590
for solver in ['lbfgs', 'liblinear']:
591-
clf_sw_none = LR(solver=solver, fit_intercept=False)
591+
clf_sw_none = LR(solver=solver, fit_intercept=False,
592+
random_state=42)
592593
clf_sw_none.fit(X, y)
593-
clf_sw_ones = LR(solver=solver, fit_intercept=False)
594+
clf_sw_ones = LR(solver=solver, fit_intercept=False,
595+
random_state=42)
594596
clf_sw_ones.fit(X, y, sample_weight=np.ones(y.shape[0]))
595597
assert_array_almost_equal(
596598
clf_sw_none.coef_, clf_sw_ones.coef_, decimal=4)
597599

598600
# Test that sample weights work the same with the lbfgs,
599601
# newton-cg, and 'sag' solvers
600-
clf_sw_lbfgs = LR(solver='lbfgs', fit_intercept=False)
602+
clf_sw_lbfgs = LR(solver='lbfgs', fit_intercept=False, random_state=42)
601603
clf_sw_lbfgs.fit(X, y, sample_weight=sample_weight)
602-
clf_sw_n = LR(solver='newton-cg', fit_intercept=False)
604+
clf_sw_n = LR(solver='newton-cg', fit_intercept=False, random_state=42)
603605
clf_sw_n.fit(X, y, sample_weight=sample_weight)
604-
clf_sw_sag = LR(solver='sag', fit_intercept=False, tol=1e-10)
606+
clf_sw_sag = LR(solver='sag', fit_intercept=False, tol=1e-10,
607+
random_state=42)
605608
# ignore convergence warning due to small dataset
606609
with ignore_warnings():
607610
clf_sw_sag.fit(X, y, sample_weight=sample_weight)
608-
clf_sw_liblinear = LR(solver='liblinear', fit_intercept=False)
611+
clf_sw_liblinear = LR(solver='liblinear', fit_intercept=False,
612+
random_state=42)
609613
clf_sw_liblinear.fit(X, y, sample_weight=sample_weight)
610614
assert_array_almost_equal(
611615
clf_sw_lbfgs.coef_, clf_sw_n.coef_, decimal=4)
@@ -619,9 +623,9 @@ def test_logistic_regression_sample_weights():
619623
# to be 2 for all instances of class 2
620624
for solver in ['lbfgs', 'liblinear']:
621625
clf_cw_12 = LR(solver=solver, fit_intercept=False,
622-
class_weight={0: 1, 1: 2})
626+
class_weight={0: 1, 1: 2}, random_state=42)
623627
clf_cw_12.fit(X, y)
624-
clf_sw_12 = LR(solver=solver, fit_intercept=False)
628+
clf_sw_12 = LR(solver=solver, fit_intercept=False, random_state=42)
625629
clf_sw_12.fit(X, y, sample_weight=sample_weight)
626630
assert_array_almost_equal(
627631
clf_cw_12.coef_, clf_sw_12.coef_, decimal=4)
@@ -630,19 +634,21 @@ def test_logistic_regression_sample_weights():
630634
# since the patched liblinear code is different.
631635
clf_cw = LogisticRegression(
632636
solver="liblinear", fit_intercept=False, class_weight={0: 1, 1: 2},
633-
penalty="l1", tol=1e-5)
637+
penalty="l1", tol=1e-5, random_state=42)
634638
clf_cw.fit(X, y)
635639
clf_sw = LogisticRegression(
636-
solver="liblinear", fit_intercept=False, penalty="l1", tol=1e-5)
640+
solver="liblinear", fit_intercept=False, penalty="l1", tol=1e-5,
641+
random_state=42)
637642
clf_sw.fit(X, y, sample_weight)
638643
assert_array_almost_equal(clf_cw.coef_, clf_sw.coef_, decimal=4)
639644

640645
clf_cw = LogisticRegression(
641646
solver="liblinear", fit_intercept=False, class_weight={0: 1, 1: 2},
642-
penalty="l2", dual=True)
647+
penalty="l2", dual=True, random_state=42)
643648
clf_cw.fit(X, y)
644649
clf_sw = LogisticRegression(
645-
solver="liblinear", fit_intercept=False, penalty="l2", dual=True)
650+
solver="liblinear", fit_intercept=False, penalty="l2", dual=True,
651+
random_state=42)
646652
clf_sw.fit(X, y, sample_weight)
647653
assert_array_almost_equal(clf_cw.coef_, clf_sw.coef_, decimal=4)
648654

0 commit comments

Comments
 (0)