<commit_before>==================================================
Clone Override Protocol with ``__sklearn_clone__``
==================================================

:Author: <NAME>
:Status: Draft
:Type: Standards Track
:Created: 2022-03-19
:Resolution: (required for Accepted | Rejected | Withdrawn)

Abstract
--------

The ability to clone Scikit-learn estimators -- removing any state due to
previous fitting -- is essential to ensuring estimator configurations are
reusable across multiple instances in cross validation.
A centralised implementation of :func:`sklearn.base.clone` regards
an estimator's constructor parameters as the state that should be copied.
This proposal allows for an estimator class to implment custom cloning
functionality with a ``__sklearn_clone__`` method, which will default to
the current ``clone`` behaviour.

Detailed description
--------------------

Cloning estimators is one way that Scikit-learn ensures that there is no
data leakage across data splits in cross-validation: by only copying an
estimator's configuration, with no data from previous fitting, the
estimator must fit with a cold start.  Cloning an estimator often also
occurs prior to parallelism, ensuring that a minimal version of the
estimator -- without a large stored model -- is serialised and distributed.

Cloning is currently governed by the implementation of
:func:`sklearn.base.clone`, which recursively descends and copies the
parameters of the passed object. For an estimator, it constructs a new
instance of the estimator's class, passing to it cloned versions of the
parameter values returned by its ``get_params``. It then performs some
sanity checks to ensure that the values passed to the construtor are
identical to what is then returned by the clone's ``get_params``.

The current equivalence between constructor parameters and what is cloned
means that whenever an estimator or library developer deems it necessary
to have further configuration of an estimator reproduced in a clone,
they must include this configuration as a constructor parameter.

Cases where this need has been raised in Scikit-learn development include:

* ensuring metadata requests are cloned with an estimator
* ensuring parameter spaces are cloned with an estimator
* building a simple wrapper that can "freeze" a pre-fitted estimator
* allowing existing options for using prefitted models in ensembles
  to work under cloning

The current design also limits the ability for an estimator developer to
define an exception to the sanity checks (see :issue:`15371`).

This proposal empowers estimator developers to extend the base implementation
of ``clone`` by providing a ``__sklearn_clone__`` method, which ``clone`` will
delegate to when available. The default implementaton will match current
``clone`` behaviour. It will be provided through
``BaseEstimator.__sklearn_clone__`` but also
provided for estimators not inheriting from :obj:`~sklearn.base.BaseEstimator`.

This shifts the paradigm from ``clone`` being a fixed operation that
Scikit-learn must be able to perform on an estimator to ``clone`` being a
behaviour that each Scikit-learn compatible estimator may implement.
Developers that define ``__sklearn_clone__`` are expected to be responsible
in maintaintaining the fundamental properties of cloning, ordinarily
through use of ``super().__sklearn_clone__``.

Implementation
--------------
<commit_msg>re estimator_checks<commit_after>==================================================
Clone Override Protocol with ``__sklearn_clone__``
==================================================

:Author: <NAME>
:Status: Draft
:Type: Standards Track
:Created: 2022-03-19
:Resolution: (required for Accepted | Rejected | Withdrawn)

Abstract
--------

The ability to clone Scikit-learn estimators -- removing any state due to
previous fitting -- is essential to ensuring estimator configurations are
reusable across multiple instances in cross validation.
A centralised implementation of :func:`sklearn.base.clone` regards
an estimator's constructor parameters as the state that should be copied.
This proposal allows for an estimator class to implment custom cloning
functionality with a ``__sklearn_clone__`` method, which will default to
the current ``clone`` behaviour.

Detailed description
--------------------

Cloning estimators is one way that Scikit-learn ensures that there is no
data leakage across data splits in cross-validation: by only copying an
estimator's configuration, with no data from previous fitting, the
estimator must fit with a cold start.  Cloning an estimator often also
occurs prior to parallelism, ensuring that a minimal version of the
estimator -- without a large stored model -- is serialised and distributed.

Cloning is currently governed by the implementation of
:func:`sklearn.base.clone`, which recursively descends and copies the
parameters of the passed object. For an estimator, it constructs a new
instance of the estimator's class, passing to it cloned versions of the
parameter values returned by its ``get_params``. It then performs some
sanity checks to ensure that the values passed to the construtor are
identical to what is then returned by the clone's ``get_params``.

The current equivalence between constructor parameters and what is cloned
means that whenever an estimator or library developer deems it necessary
to have further configuration of an estimator reproduced in a clone,
they must include this configuration as a constructor parameter.

Cases where this need has been raised in Scikit-learn development include:

* ensuring metadata requests are cloned with an estimator
* ensuring parameter spaces are cloned with an estimator
* building a simple wrapper that can "freeze" a pre-fitted estimator
* allowing existing options for using prefitted models in ensembles
  to work under cloning

The current design also limits the ability for an estimator developer to
define an exception to the sanity checks (see :issue:`15371`).

This proposal empowers estimator developers to extend the base implementation
of ``clone`` by providing a ``__sklearn_clone__`` method, which ``clone`` will
delegate to when available. The default implementaton will match current
``clone`` behaviour. It will be provided through
``BaseEstimator.__sklearn_clone__`` but also
provided for estimators not inheriting from :obj:`~sklearn.base.BaseEstimator`.

This shifts the paradigm from ``clone`` being a fixed operation that
Scikit-learn must be able to perform on an estimator to ``clone`` being a
behaviour that each Scikit-learn compatible estimator may implement.

Developers that define ``__sklearn_clone__`` are expected to be responsible
in maintaintaining the fundamental properties of cloning. Ordinarily, they
can achieve this through use of ``super().__sklearn_clone__``. Core behaviours,
such as constructor parameters being preserved through ``clone`` operations,
can be ensured through estimator checks.

Implementation
--------------

{'fraction_non_alphanumeric': 0.08689438330713163, 'fraction_numerical': 0.0037158782335286553, 'mean_word_length': 5.181978798586573, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '73964', 'n_tokens_mistral': 1686, 'n_tokens_neox': 1552, 'n_words': 904}