Thanks to visit codestin.com
Credit goes to github.com

Skip to content

API deprecate penalty='none' for LogisticRegression #23877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/whats_new/v1.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ Changelog
to `"highs"` in version 1.4.
:pr:`23637` by :user:`Guillaume Lemaitre <glemaitre>`.

- |API| String option `"none"` is deprecated for `penalty` argument
in :class:`linear_model.LogisticRegression`, and will be removed in version 1.4.
Use `None` instead. :pr:`23877` by :user:`Zhehao Liu <MaxwellLZH>`.

:mod:`sklearn.metrics`
......................

Expand Down
35 changes: 26 additions & 9 deletions sklearn/linear_model/_logistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@

def _check_solver(solver, penalty, dual):

if solver not in ["liblinear", "saga"] and penalty not in ("l2", "none"):
# TODO(1.4): Remove "none" option
if solver not in ["liblinear", "saga"] and penalty not in ("l2", "none", None):
raise ValueError(
"Solver %s supports only 'l2' or 'none' penalties, got %s penalty."
% (solver, penalty)
Expand Down Expand Up @@ -766,10 +767,10 @@ class LogisticRegression(LinearClassifierMixin, SparseCoefMixin, BaseEstimator):

Parameters
----------
penalty : {'l1', 'l2', 'elasticnet', 'none'}, default='l2'
penalty : {'l1', 'l2', 'elasticnet', None}, default='l2'
Specify the norm of the penalty:

- `'none'`: no penalty is added;
- `None`: no penalty is added;
- `'l2'`: add a L2 penalty term and it is the default choice;
- `'l1'`: add a L1 penalty term;
- `'elasticnet'`: both L1 and L2 penalty terms are added.
Expand All @@ -782,6 +783,10 @@ class LogisticRegression(LinearClassifierMixin, SparseCoefMixin, BaseEstimator):
.. versionadded:: 0.19
l1 penalty with SAGA solver (allowing 'multinomial' + L1)

.. deprecated:: 1.2
The 'none' option was deprecated in version 1.2, and will be removed
in 1.4. Use `None` instead.

dual : bool, default=False
Dual or primal formulation. Dual formulation is only implemented for
l2 penalty with liblinear solver. Prefer dual=False when
Expand Down Expand Up @@ -846,11 +851,11 @@ class LogisticRegression(LinearClassifierMixin, SparseCoefMixin, BaseEstimator):
The choice of the algorithm depends on the penalty chosen:
Supported penalties by solver:

- 'newton-cg' - ['l2', 'none']
- 'lbfgs' - ['l2', 'none']
- 'newton-cg' - ['l2', None]
- 'lbfgs' - ['l2', None]
- 'liblinear' - ['l1', 'l2']
- 'sag' - ['l2', 'none']
- 'saga' - ['elasticnet', 'l1', 'l2', 'none']
- 'sag' - ['l2', None]
- 'saga' - ['elasticnet', 'l1', 'l2', None]

.. note::
'sag' and 'saga' fast convergence is only guaranteed on
Expand Down Expand Up @@ -1012,7 +1017,11 @@ class LogisticRegression(LinearClassifierMixin, SparseCoefMixin, BaseEstimator):
"""

_parameter_constraints = {
"penalty": [StrOptions({"l1", "l2", "elasticnet", "none"})],
# TODO(1.4): Remove "none" option
"penalty": [
StrOptions({"l1", "l2", "elasticnet", "none"}, deprecated={"none"}),
None,
],
"dual": ["boolean"],
"tol": [Interval(Real, 0, None, closed="left")],
"C": [Interval(Real, 0, None, closed="right")],
Expand Down Expand Up @@ -1106,10 +1115,18 @@ def fit(self, X, y, sample_weight=None):
"(penalty={})".format(self.penalty)
)

# TODO(1.4): Remove "none" option
if self.penalty == "none":
warnings.warn(
"`penalty='none'`has been deprecated in 1.2 and will be removed in 1.4."
" To keep the past behaviour, set `penalty=None`.",
FutureWarning,
)

if self.penalty is None or self.penalty == "none":
if self.C != 1.0: # default values
warnings.warn(
"Setting penalty='none' will ignore the C and l1_ratio parameters"
"Setting penalty=None will ignore the C and l1_ratio parameters"
)
# Note that check for l1_ratio is done right above
C_ = np.inf
Expand Down
8 changes: 4 additions & 4 deletions sklearn/linear_model/_stochastic_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,11 +964,11 @@ class SGDClassifier(BaseSGDClassifier):
The loss 'log' was deprecated in v1.1 and will be removed
in version 1.3. Use `loss='log_loss'` which is equivalent.

penalty : {'l2', 'l1', 'elasticnet'}, default='l2'
penalty : {'l2', 'l1', 'elasticnet', None}, default='l2'
The penalty (aka regularization term) to be used. Defaults to 'l2'
which is the standard regularizer for linear SVM models. 'l1' and
'elasticnet' might bring sparsity to the model (feature selection)
not achievable with 'l2'.
not achievable with 'l2'. No penalty is added when set to `None`.

alpha : float, default=0.0001
Constant that multiplies the regularization term. The higher the
Expand Down Expand Up @@ -1773,11 +1773,11 @@ class SGDRegressor(BaseSGDRegressor):
The loss 'squared_loss' was deprecated in v1.0 and will be removed
in version 1.2. Use `loss='squared_error'` which is equivalent.

penalty : {'l2', 'l1', 'elasticnet'}, default='l2'
penalty : {'l2', 'l1', 'elasticnet', None}, default='l2'
The penalty (aka regularization term) to be used. Defaults to 'l2'
which is the standard regularizer for linear SVM models. 'l1' and
'elasticnet' might bring sparsity to the model (feature selection)
not achievable with 'l2'.
not achievable with 'l2'. No penalty is added when set to `None`.

alpha : float, default=0.0001
Constant that multiplies the regularization term. The higher the
Expand Down
23 changes: 18 additions & 5 deletions sklearn/linear_model/tests/test_logistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1772,18 +1772,18 @@ def fit(X, y, **kw):

@pytest.mark.parametrize("solver", ("lbfgs", "newton-cg", "sag", "saga"))
def test_penalty_none(solver):
# - Make sure warning is raised if penalty='none' and C is set to a
# - Make sure warning is raised if penalty=None and C is set to a
# non-default value.
# - Make sure setting penalty='none' is equivalent to setting C=np.inf with
# - Make sure setting penalty=None is equivalent to setting C=np.inf with
# l2 penalty.
X, y = make_classification(n_samples=1000, random_state=0)

msg = "Setting penalty='none' will ignore the C"
lr = LogisticRegression(penalty="none", solver=solver, C=4)
msg = "Setting penalty=None will ignore the C"
lr = LogisticRegression(penalty=None, solver=solver, C=4)
with pytest.warns(UserWarning, match=msg):
lr.fit(X, y)

lr_none = LogisticRegression(penalty="none", solver=solver, random_state=0)
lr_none = LogisticRegression(penalty=None, solver=solver, random_state=0)
lr_l2_C_inf = LogisticRegression(
penalty="l2", C=np.inf, solver=solver, random_state=0
)
Expand Down Expand Up @@ -1971,3 +1971,16 @@ def test_single_feature_newton_cg():
y = np.array([1, 1, 0, 0, 1, 1, 0, 1])
assert X.shape[1] == 1
LogisticRegression(solver="newton-cg", fit_intercept=True).fit(X, y)


# TODO(1.4): Remove
def test_warning_on_penalty_string_none():
# Test that warning message is shown when penalty='none'
target = iris.target_names[iris.target]
lr = LogisticRegression(penalty="none")
warning_message = (
"`penalty='none'`has been deprecated in 1.2 and will be removed in 1.4."
" To keep the past behaviour, set `penalty=None`."
)
with pytest.warns(FutureWarning, match=warning_message):
lr.fit(iris.data, target)