Repository: scikit-learn/scikit-learn
File: examples/release_highlights/plot_release_highlights_1_8_0.py (Python)

Code before:
# changes.
#
# Efficiency of squared error based models with L1 penalty
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# The first one is a massive improvement of efficiency, in particular a reduced fit
# time, for squared error based estimators with L1 penalty: `ElasticNet`, `Lasso`,
# `MultiTaskElasticNet`, `MultiTaskLasso` and their CV variants. The fit time
# improvement is mainly achieved by **gap safe screening rules**. They enable the
# coordinate descent solver to set feature coefficients early to 0 and not look at them
# again. The stronger the L1 penalty the earlier features can be excluded from further
# updates.

from time import time

from sklearn.datasets import make_regression
from sklearn.linear_model import ElasticNetCV

X, y = make_regression(n_features=5000)
model = ElasticNetCV()
tic = time()
model.fit(X, y)
toc = time()
print(f"Fitting ElasticNetCV took {toc - tic:.3} seconds.")

# %%
# API changes in logistic regression
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# After the deprecation (version 1.5) and removal (now in 1.8) of the `multi_class`
# parameter in `LogisticRegression` and `LogisticRegressionCV`, the bookkeeping goes
# on. The goal for `LogisticRegressionCV` is to fix types and shapes of a few fitted
# attributes: `C_`, `l1_ratio_`, `coefs_paths_`, `scores_`, `n_iter_`. To ease the
# transition, you can choose between new and old types and shapes with the new and
# temporary parameter `use_legacy_attributes`.

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegressionCV

X, y = make_classification(n_classes=3, n_informative=4)
model = LogisticRegressionCV(
    use_legacy_attributes=True, l1_ratios=(0,), solver="newton-cholesky"
).fit(X, y)
model.C_  # ndarray of shape (3,), 3 times the same value
model = LogisticRegressionCV(
    use_legacy_attributes=False, l1_ratios=(0,), solver="newton-cholesky"
).fit(X, y)
model.C_  # single float

# %%
# A further deprecation is going on for the `penalty` parameter in both
# `LogisticRegression` and `LogisticRegressionCV`. It is redundant because `C` together
# with `l1_ratio` for `LogisticRegression` and `l1_ratios` for `LogisticRegressionCV`

Review comment (suggestion):
Thanks for writing this! I am a bit undecided about mentioning the `Logisticregression{,CV}` deprecations in the release highlights.

Part of me thinks that deprecations are not so "crucial" and don't really belong in the release highlights. Part of me thinks that the `LogisticRegression{,CV}` changes may catch a few users and it would be nice to have a good place where they are summarized. Right now, my feeling is that they are a bit scattered in the changelog and in the docstrings.

Code after:
#     )
#     with sklearn.config_context(array_api_dispatch=True):
#         cv_results = cross_validate(ridge_pipeline_gpu, features, target)
#
#
# See the `full notebook on Google Colab
# <https://colab.research.google.com/drive/1ztH8gUPv31hSjEeR_8pw20qShTwViGRx?usp=sharing>`_
# for more details. On this particular example, using the Colab GPU vs using a
# single CPU core leads to a 10x speedup which is quite typical for such workloads.

# %%
# Free-threaded CPython 3.14 support
# ----------------------------------
#
# scikit-learn has support for free-threaded CPython, in particular
# free-threaded wheels are available for all of our supported platforms on Python
# 3.14.
#
# We would be very interested by user feedback. Here are a few things you can
# try:
#
# - install free-threaded CPython 3.14, run your favourite
#   scikit-learn script and check that nothing breaks unexpectedly.
#   Note that CPython 3.14 (rather than 3.13) is strongly advised because a
#   number of free-threaded bugs have been fixed since CPython 3.13.
# - if you use some estimators with a `n_jobs` parameter, try changing the
#   default backend to threading with `joblib.parallel_config` as in the
#   snippet below. This could potentially speed-up your code because the
#   default joblib backend is process-based and incurs more overhead than
#   threads.
#
#   .. code-block:: python
#
#       grid_search = GridSearchCV(clf, param_grid=param_grid, n_jobs=4)
#       with joblib.parallel_config(backend="threading"):
#           grid_search.fit(X, y)
#
# - don't hesitate to report any issue or unexpected performance behaviour by
#   opening a `GitHub issue <https://github.com/scikit-learn/scikit-learn/issues/new/choose>`_!
#
# Free-threaded (also known as nogil) CPython is a version of CPython that aims
# to enable efficient multi-threaded use cases by removing the Global
# Interpreter Lock (GIL).
#
# For more details about free-threaded CPython see `py-free-threading doc
# <https://py-free-threading.github.io>`_, in particular `how to install a
# free-threaded CPython <https://py-free-threading.github.io/installing-cpython/>`_
# and `Ecosystem compatibility tracking <https://py-free-threading.github.io/tracking/>`_.
#
# In scikit-learn, one hope with free-threaded Python is to more efficiently
# leverage multi-core CPUs by using thread workers instead of subprocess