Skip to content

Fixes API Deprecate n_alphas in LinearModelCV #30616

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 10 commits into from
Apr 23, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
The parameter `n_alphas` has been deprecated in the following classes:
:class:`linear_model.ElasticNetCV` and :class:`linear_model.LassoCV`
and :class:`linear_model.MultiTaskElasticNetCV`
and :class:`linear_model.MultiTaskLassoCV`, and will be removed in 1.9. The parameter
`alphas` now supports both integers and array-likes, removing the need for `n_alphas`.
From now on, only `alphas` should be set to either indicate the number of alphas to
automatically generate (int) or to provide a list of alphas (array-like) to test along
the regularization path.
By :user:`Siddharth Bansal <KANNAHWORLD >`.
156 changes: 125 additions & 31 deletions sklearn/linear_model/_coordinate_descent.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
_raise_for_params,
get_routing_for_object,
)
from ..utils._param_validation import Interval, StrOptions, validate_params
from ..utils._param_validation import Hidden, Interval, StrOptions, validate_params
from ..utils.extmath import safe_sparse_dot
from ..utils.metadata_routing import (
_routing_enabled,
Expand Down Expand Up @@ -1493,8 +1493,17 @@ class LinearModelCV(MultiOutputMixin, LinearModel, ABC):

_parameter_constraints: dict = {
"eps": [Interval(Real, 0, None, closed="neither")],
"n_alphas": [Interval(Integral, 1, None, closed="left")],
"alphas": ["array-like", None],
"n_alphas": [
Interval(Integral, 1, None, closed="left"),
Hidden(StrOptions({"deprecated"})),
],
# TODO(1.9): remove "warn" and None options.
"alphas": [
Interval(Integral, 1, None, closed="left"),
"array-like",
None,
Hidden(StrOptions({"warn"})),
],
"fit_intercept": ["boolean"],
"precompute": [StrOptions({"auto"}), "array-like", "boolean"],
"max_iter": [Interval(Integral, 1, None, closed="left")],
Expand All @@ -1512,8 +1521,8 @@ class LinearModelCV(MultiOutputMixin, LinearModel, ABC):
def __init__(
self,
eps=1e-3,
n_alphas=100,
alphas=None,
n_alphas="deprecated",
alphas="warn",
fit_intercept=True,
precompute="auto",
max_iter=1000,
Expand Down Expand Up @@ -1595,6 +1604,40 @@ def fit(self, X, y, sample_weight=None, **params):
"""
_raise_for_params(params, self, "fit")

# TODO(1.9): remove n_alphas and alphas={"warn", None}; set alphas=100 by
# default. Remove these deprecations messages and use self.alphas directly
# instead of self._alphas.
if self.n_alphas == "deprecated":
self._alphas = 100
else:
warnings.warn(
"'n_alphas' was deprecated in 1.7 and will be removed in 1.9. "
"'alphas' now accepts an integer value which removes the need to pass "
"'n_alphas'. The default value of 'alphas' will change from None to "
"100 in 1.9. Pass an explicit value to 'alphas' and leave 'n_alphas' "
"to its default value to silence this warning.",
FutureWarning,
)
self._alphas = self.n_alphas

if isinstance(self.alphas, str) and self.alphas == "warn":
# - If self.n_alphas == "deprecated", both are left to their default values
# so we don't warn since the future default behavior will be the same as
# the current default behavior.
# - If self.n_alphas != "deprecated", then we already warned about it
# and the warning message mentions the future self.alphas default, so
# no need to warn a second time.
pass
elif self.alphas is None:
warnings.warn(
"'alphas=None' is deprecated and will be removed in 1.9, at which "
"point the default value will be set to 100. Set 'alphas=100' "
"to silence this warning.",
FutureWarning,
)
else:
self._alphas = self.alphas

# This makes sure that there is no duplication in memory.
# Dealing right with copy_X is important in the following:
# Multiple functions touch X and subsamples of X and can induce a
Expand Down Expand Up @@ -1692,7 +1735,6 @@ def fit(self, X, y, sample_weight=None, **params):
path_params.pop("cv", None)
path_params.pop("n_jobs", None)

alphas = self.alphas
n_l1_ratio = len(l1_ratios)

check_scalar_alpha = partial(
Expand All @@ -1702,26 +1744,26 @@ def fit(self, X, y, sample_weight=None, **params):
include_boundaries="left",
)

if alphas is None:
if isinstance(self._alphas, Integral):
alphas = [
_alpha_grid(
X,
y,
l1_ratio=l1_ratio,
fit_intercept=self.fit_intercept,
eps=self.eps,
n_alphas=self.n_alphas,
n_alphas=self._alphas,
copy_X=self.copy_X,
sample_weight=sample_weight,
)
for l1_ratio in l1_ratios
]
else:
# Making sure alphas entries are scalars.
for index, alpha in enumerate(alphas):
for index, alpha in enumerate(self._alphas):
check_scalar_alpha(alpha, f"alphas[{index}]")
# Making sure alphas is properly ordered.
alphas = np.tile(np.sort(alphas)[::-1], (n_l1_ratio, 1))
alphas = np.tile(np.sort(self._alphas)[::-1], (n_l1_ratio, 1))

# We want n_alphas to be the number of alphas used for each l1_ratio.
n_alphas = len(alphas[0])
Expand Down Expand Up @@ -1807,7 +1849,7 @@ def fit(self, X, y, sample_weight=None, **params):

self.l1_ratio_ = best_l1_ratio
self.alpha_ = best_alpha
if self.alphas is None:
if isinstance(self._alphas, Integral):
self.alphas_ = np.asarray(alphas)
if n_l1_ratio == 1:
self.alphas_ = self.alphas_[0]
Expand Down Expand Up @@ -1897,9 +1939,22 @@ class LassoCV(RegressorMixin, LinearModelCV):
n_alphas : int, default=100
Number of alphas along the regularization path.

alphas : array-like, default=None
List of alphas where to compute the models.
If ``None`` alphas are set automatically.
.. deprecated:: 1.7
`n_alphas` was deprecated in 1.7 and will be removed in 1.9. Use `alphas`
instead.

alphas : array-like or int, default=None
Values of alphas to test along the regularization path.
If int, `alphas` values are generated automatically.
If array-like, list of alpha values to use.

.. versionchanged:: 1.7
`alphas` accepts an integer value which removes the need to pass
`n_alphas`.

.. deprecated:: 1.7
`alphas=None` was deprecated in 1.7 and will be removed in 1.9, at which
point the default value will be set to 100.

fit_intercept : bool, default=True
Whether to calculate the intercept for this model. If set
Expand Down Expand Up @@ -2049,8 +2104,8 @@ def __init__(
self,
*,
eps=1e-3,
n_alphas=100,
alphas=None,
n_alphas="deprecated",
alphas="warn",
fit_intercept=True,
precompute="auto",
max_iter=1000,
Expand Down Expand Up @@ -2155,9 +2210,22 @@ class ElasticNetCV(RegressorMixin, LinearModelCV):
n_alphas : int, default=100
Number of alphas along the regularization path, used for each l1_ratio.

alphas : array-like, default=None
List of alphas where to compute the models.
If None alphas are set automatically.
.. deprecated:: 1.7
`n_alphas` was deprecated in 1.7 and will be removed in 1.9. Use `alphas`
instead.

alphas : array-like or int, default=None
Values of alphas to test along the regularization path, used for each l1_ratio.
If int, `alphas` values are generated automatically.
If array-like, list of alpha values to use.

.. versionchanged:: 1.7
`alphas` accepts an integer value which removes the need to pass
`n_alphas`.

.. deprecated:: 1.7
`alphas=None` was deprecated in 1.7 and will be removed in 1.9, at which
point the default value will be set to 100.

fit_intercept : bool, default=True
Whether to calculate the intercept for this model. If set
Expand Down Expand Up @@ -2326,8 +2394,8 @@ def __init__(
*,
l1_ratio=0.5,
eps=1e-3,
n_alphas=100,
alphas=None,
n_alphas="deprecated",
alphas="warn",
fit_intercept=True,
precompute="auto",
max_iter=1000,
Expand Down Expand Up @@ -2845,9 +2913,22 @@ class MultiTaskElasticNetCV(RegressorMixin, LinearModelCV):
n_alphas : int, default=100
Number of alphas along the regularization path.

alphas : array-like, default=None
List of alphas where to compute the models.
If not provided, set automatically.
.. deprecated:: 1.7
`n_alphas` was deprecated in 1.7 and will be removed in 1.9. Use `alphas`
instead.

alphas : array-like or int, default=None
Values of alphas to test along the regularization path, used for each l1_ratio.
If int, `alphas` values are generated automatically.
If array-like, list of alpha values to use.

.. versionchanged:: 1.7
`alphas` accepts an integer value which removes the need to pass
`n_alphas`.

.. deprecated:: 1.7
`alphas=None` was deprecated in 1.7 and will be removed in 1.9, at which
point the default value will be set to 100.

fit_intercept : bool, default=True
Whether to calculate the intercept for this model. If set
Expand Down Expand Up @@ -2991,8 +3072,8 @@ def __init__(
*,
l1_ratio=0.5,
eps=1e-3,
n_alphas=100,
alphas=None,
n_alphas="deprecated",
alphas="warn",
fit_intercept=True,
max_iter=1000,
tol=1e-4,
Expand Down Expand Up @@ -3088,9 +3169,22 @@ class MultiTaskLassoCV(RegressorMixin, LinearModelCV):
n_alphas : int, default=100
Number of alphas along the regularization path.

alphas : array-like, default=None
List of alphas where to compute the models.
If not provided, set automatically.
.. deprecated:: 1.7
`n_alphas` was deprecated in 1.7 and will be removed in 1.9. Use `alphas`
instead.

alphas : array-like or int, default=None
Values of alphas to test along the regularization path.
If int, `alphas` values are generated automatically.
If array-like, list of alpha values to use.

.. versionchanged:: 1.7
`alphas` accepts an integer value which removes the need to pass
`n_alphas`.

.. deprecated:: 1.7
`alphas=None` was deprecated in 1.7 and will be removed in 1.9, at which
point the default value will be set to 100.

fit_intercept : bool, default=True
Whether to calculate the intercept for this model. If set
Expand Down Expand Up @@ -3230,8 +3324,8 @@ def __init__(
self,
*,
eps=1e-3,
n_alphas=100,
alphas=None,
n_alphas="deprecated",
alphas="warn",
fit_intercept=True,
max_iter=1000,
tol=1e-4,
Expand Down
Loading