Name | sklearn-compat JSON |
Version |
0.1.3
JSON |
| download |
home_page | None |
Summary | Ease support for compatible scikit-learn estimators across versions |
upload_time | 2024-12-21 14:29:06 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | None |
keywords |
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Ease multi-version support for scikit-learn compatible library
[](https://scientific-python.org/specs/spec-0000/)

[](https://codecov.io/gh/sklearn-compat/sklearn-compat)
[](https://img.shields.io/pypi/pyversions/sklearn-compat.svg)
[](https://badge.fury.io/py/sklearn-compat.svg)
`sklearn-compat` is a small Python package that help developer writing scikit-learn
compatible estimators to support multiple scikit-learn versions. Note that we provide
a vendorable version of this package in the `src/sklearn_compat/_sklearn_compat.py`
file if you do not want to depend on `sklearn-compat` as a package. The package is
available on [PyPI](https://pypi.org/project/sklearn-compat/) and on
[conda-forge](https://anaconda.org/conda-forge/sklearn-compat).
As maintainers of third-party libraries depending on scikit-learn such as
[`imbalanced-learn`](https://github.com/scikit-learn-contrib/imbalanced-learn),
[`skrub`](https://github.com/skrub-data/skrub), or
[`skops`](https://github.com/skops-dev/skops), we usually identified small breaking
changes on the "private" developer utilities of `scikit-learn`. Indeed, each of these
third-party libraries code the exact same utilities when it comes to support multiple
`scikit-learn` versions. We therefore decided to factorize these utilities in a
dedicated package that we update at each `scikit-learn` release.
When it comes to support multiple `scikit-learn` versions, the initial plan as of
December 2024 is to follow the [SPEC0](https://scientific-python.org/specs/spec-0000/)
recommendations. It means that this utility will support **at least** the `scikit-learn`
versions up to 2 years or about 4 versions. The current version of `sklearn-compat`
supports `scikit-learn` >= 1.2.
## How to adapt your scikit-learn code
In this section, we describe succinctly the changes you need to do to your code to
support multiple `scikit-learn` versions using `sklearn-compat` as a package. If you
use the vendored version of `sklearn-compat`, all imports will be changed from:
``` py
from sklearn_compat.any_submodule import any_function
```
to
``` py
from path.to._sklearn_compat import any_function
```
where `_sklearn_compat` is the vendored version of `sklearn-compat` in your project.
### Upgrading to scikit-learn 1.6
#### `is_clusterer` function
The function `is_clusterer` has been added in `scikit-learn` 1.6. So we backport it
such that you can have access to it in scikit-learn 1.2+. The pattern is the following:
``` py
from sklearn.cluster import KMeans
from sklearn_compat.base import is_clusterer
is_clusterer(KMeans())
```
#### `validate_data` function
Your previous code could have looked like this:
``` py
class MyEstimator(BaseEstimator):
def fit(self, X, y=None):
X = self._validate_data(X, force_all_finite=True)
return self
```
There is two major changes in scikit-learn 1.6:
- `validate_data` has been moved to `sklearn.utils.validation`.
- `force_all_finite` is deprecated in favor of the `ensure_all_finite` parameter.
You can now use the following code for backward compatibility:
``` py
from sklearn_compat.utils.validation import validate_data
class MyEstimator(BaseEstimator):
def fit(self, X, y=None):
X = validate_data(self, X=X, ensure_all_finite=True)
return self
```
#### `check_array` and `check_X_y` functions
The parameter `force_all_finite` has been deprecated in favor of the `ensure_all_finite`
parameter. You need to modify the call to the function to use the new parameter. So,
the change is the same as for `validate_data` and will look like this:
``` py
from sklearn.utils.validation import check_array, check_X_y
check_array(X, force_all_finite=True)
check_X_y(X, y, force_all_finite=True)
```
to:
``` py
from sklearn_compat.utils.validation import check_array, check_X_y
check_array(X, ensure_all_finite=True)
check_X_y(X, y, ensure_all_finite=True)
```
#### `_check_n_features` and `_check_feature_names` functions
Similarly to `validate_data`, these two functions have been moved to
`sklearn.utils.validation` instead of being methods of the estimators. So the following
code:
``` py
class MyEstimator(BaseEstimator):
def fit(self, X, y=None):
self._check_n_features(X, reset=True)
self._check_feature_names(X, reset=True)
return self
```
becomes:
``` py
from sklearn_compat.utils.validation import _check_n_features, _check_feature_names
class MyEstimator(BaseEstimator):
def fit(self, X, y=None):
_check_n_features(self, X, reset=True)
_check_feature_names(self, X, reset=True)
return self
```
Note that it is best to call `validate_data` with `skip_check_array=True` instead of
calling these private functions. See the section above regarding `validate_data`.
#### `Tags`, `__sklearn_tags__` and estimator tags
The estimator tags infrastructure in scikit-learn 1.6 has changed. In order to be
compatible with multiple scikit-learn versions, your estimator should implement both
`_more_tags` and `__sklearn_tags__`:
``` py
class MyEstimator(BaseEstimator):
def _more_tags(self):
return {"non_deterministic": True, "poor_score": True}
def __sklearn_tags__(self):
tags = super().__sklearn_tags__()
tags.non_deterministic = True
tags.regressor_tags.poor_score = True
return tags
```
In order to get the tags of a given estimator, you can use the `get_tags` function:
``` py
from sklearn_compat.utils import get_tags
tags = get_tags(MyEstimator())
```
Which uses `sklearn.utils.get_tags` under the hood from scikit-learn 1.6+.
In case you want to extend the tags, you can inherit from the available tags:
```py
from sklearn_compat.utils._tags import Tags, InputTags
class MyInputTags(InputTags):
dataframe: bool = False
class MyEstimator(BaseEstimator):
def __sklearn_tags__(self):
tags = super().__sklearn_tags__()
tags.input_tags = MyInputTags(
one_d_array=tags.input_tags.one_d_array,
two_d_array=tags.input_tags.two_d_array,
sparse=tags.input_tags.sparse,
category=True,
dataframe=True,
string=tags.input_tags.string,
dict=tags.input_tags.dict,
positive_only=tags.input_tags.positive_only,
allow_nan=tags.input_tags.allow_nan,
pairwise=tags.input_tags.pairwise,
)
return tags
```
#### `check_estimator` and `parametrize_with_checks` functions
The new tags don't include a `_xfail_checks` tags, and instead, the tests which are
expected to fail are directly passed to the `check_estimator` and
`parametrize_with_checks` functions. The two functions available in this package are
compatible with the new signature, and patch the estimator in older scikit-learn
versions to include the expected failed checks in their tags so that you don't need
to include them both in your tests and in your `_xfail_checks` old tags.
``` py
from sklearn_compat.utils.testing import parametrize_with_checks
from mypackage.myestimator import MyEstimator1, MyEstimator2
EXPECTED_FAILED_CHECKS = {
"MyEstimator1": {"check_name1": "reason1", "check_name2": "reason2"},
"MyEstimator2": {"check_name3": "reason3"},
}
@parametrize_with_checks([MyEstimator1(), MyEstimator2()],
expected_failed_checks=lambda est: EXPECTED_FAILED_CHECKS.get(
est.__class__.__name__, {}
)
)
def test_my_estimator(estimator, check):
check(estimator)
```
### Upgrading to scikit-learn 1.5
In scikit-learn 1.5, many developer utilities have been moved to dedicated modules.
We provide a compatibility layer such that you don't have to check the version or try
to import the utilities from different modules.
In the future, when supporting scikit-learn 1.6+, you will have to change the import
from:
``` py
from sklearn_compat.utils._indexing import _safe_indexing
```
to
``` py
from sklearn.utils._indexing import _safe_indexing
```
Thus, the module path will already be correct. Now, we will go into details for
each module and function impacted.
#### `extmath` module
The function `safe_sqr` and `_approximate_mode` have been moved from `sklearn.utils` to
`sklearn.utils.extmath`.
So some code looking like this:
``` py
from sklearn.utils import safe_sqr, _approximate_mode
safe_sqr(np.array([1, 2, 3]))
_approximate_mode(class_counts=np.array([4, 2]), n_draws=3, rng=0)
```
becomes:
``` py
from sklearn_compat.utils.extmath import safe_sqr, _approximate_mode
safe_sqr(np.array([1, 2, 3]))
_approximate_mode(class_counts=np.array([4, 2]), n_draws=3, rng=0)
```
#### `type_of_target` function
The function `type_of_target` accepts a new parameter `raise_unknown`. This parameter is
available in the `sklearn_compat.utils.multiclass.type_of_target` function.
```py
from sklearn_compat.utils.multiclass import type_of_target
y = []
# raise an error with unknown target type
type_of_target(y, raise_unknown=True)
```
#### `fixes` module
The functions `_in_unstable_openblas_configuration`, `_IS_32BIT` and `_IS_WASM` have
been moved from `sklearn.utils` to `sklearn.utils.fixes`.
So the following code:
``` py
from sklearn.utils import (
_in_unstable_openblas_configuration,
_IS_32BIT,
_IS_WASM,
)
_in_unstable_openblas_configuration()
print(_IS_32BIT)
print(_IS_WASM)
```
becomes:
``` py
from sklearn_compat.utils.fixes import (
_in_unstable_openblas_configuration,
_IS_32BIT,
_IS_WASM,
)
_in_unstable_openblas_configuration()
print(_IS_32BIT)
print(_IS_WASM)
```
#### `validation` module
The function `_to_object_array` has been moved from `sklearn.utils` to
`sklearn.utils.validation`.
So the following code:
``` py
from sklearn.utils import _to_object_array
_to_object_array([np.array([0]), np.array([1])])
```
becomes:
``` py
from sklearn_compat.utils.validation import _to_object_array
_to_object_array([np.array([0]), np.array([1])])
```
#### `_chunking` module
The functions `gen_batches`, `gen_even_slices` and `get_chunk_n_rows` have been moved
from `sklearn.utils` to `sklearn.utils._chunking`. The function `chunk_generator` has
been moved to `sklearn.utils._chunking` as well but was renamed from `_chunk_generator`
to `chunk_generator`.
So the following code:
``` py
from sklearn.utils import (
_chunk_generator as chunk_generator,
gen_batches,
gen_even_slices,
get_chunk_n_rows,
)
_chunk_generator(range(10), 3)
gen_batches(7, 3)
gen_even_slices(10, 1)
get_chunk_n_rows(10)
```
becomes:
``` py
from sklearn_compat.utils._chunking import (
chunk_generator, gen_batches, gen_even_slices, get_chunk_n_rows,
)
chunk_generator(range(10), 3)
gen_batches(7, 3)
gen_even_slices(10, 1)
get_chunk_n_rows(10)
```
#### `_indexing` module
The utility functions `_determine_key_type`, `_safe_indexing`, `_safe_assign`,
`_get_column_indices`, `resample` and `shuffle` have been moved from `sklearn.utils` to
`sklearn.utils._indexing`.
So the following code:
``` py
import numpy as np
import pandas as pd
from sklearn.utils import (
_get_column_indices,
_safe_indexing,
_safe_assign,
resample,
shuffle,
)
_determine_key_type(np.arange(10))
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
_get_column_indices(df, key="b")
_safe_indexing(df, 1, axis=1)
_safe_assign(df, 1, np.array([7, 8, 9]))
array = np.arange(10)
resample(array, n_samples=20, replace=True, random_state=0)
shuffle(array, random_state=0)
```
becomes:
``` py
import numpy as np
import pandas as pd
from sklearn_compat.utils._indexing import (
_determine_key_type,
_safe_indexing,
_safe_assign,
_get_column_indices,
resample,
shuffle,
)
_determine_key_type(np.arange(10))
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
_get_column_indices(df, key="b")
_safe_indexing(df, 1, axis=1)
_safe_assign(df, 1, np.array([7, 8, 9]))
array = np.arange(10)
resample(array, n_samples=20, replace=True, random_state=0)
shuffle(array, random_state=0)
```
#### `_mask` module
The functions `safe_mask`, `axis0_safe_slice` and `indices_to_mask` have been moved from
`sklearn.utils` to `sklearn.utils._mask`.
So the following code:
``` py
from sklearn.utils import safe_mask, axis0_safe_slice, indices_to_mask
safe_mask(data, condition)
axis0_safe_slice(X, mask, X.shape[0])
indices_to_mask(indices, 5)
```
becomes:
``` py
from sklearn_compat.utils._mask import safe_mask, axis0_safe_slice, indices_to_mask
safe_mask(data, condition)
axis0_safe_slice(X, mask, X.shape[0])
indices_to_mask(indices, 5)
```
#### `_missing` module
The functions `is_scalar_nan` have been moved from `sklearn.utils` to
`sklearn.utils._missing`. The function `_is_pandas_na` has been moved to
`sklearn.utils._missing` as well and renamed to `is_pandas_na`.
So the following code:
``` py
from sklearn.utils import is_scalar_nan, _is_pandas_na
is_scalar_nan(float("nan"))
_is_pandas_na(float("nan"))
```
becomes:
``` py
from sklearn_compat.utils._missing import is_scalar_nan, is_pandas_na
is_scalar_nan(float("nan"))
is_pandas_na(float("nan"))
```
#### `_user_interface` module
The function `_print_elapsed_time` has been moved from `sklearn.utils` to
`sklearn.utils._user_interface`.
So the following code:
``` py
from sklearn.utils import _print_elapsed_time
with _print_elapsed_time("sklearn_compat", "testing"):
time.sleep(0.1)
```
becomes:
``` py
from sklearn_compat.utils._user_interface import _print_elapsed_time
with _print_elapsed_time("sklearn_compat", "testing"):
time.sleep(0.1)
```
#### `_optional_dependencies` module
The functions `check_matplotlib_support` and `check_pandas_support` have been moved from
`sklearn.utils` to `sklearn.utils._optional_dependencies`.
So the following code:
``` py
from sklearn.utils import check_matplotlib_support, check_pandas_support
check_matplotlib_support("sklearn_compat")
check_pandas_support("sklearn_compat")
```
becomes:
``` py
from sklearn_compat.utils._optional_dependencies import (
check_matplotlib_support, check_pandas_support
)
check_matplotlib_support("sklearn_compat")
check_pandas_support("sklearn_compat")
```
### Upgrading to scikit-learn 1.4
#### `process_routing` and `_raise_for_params` functions
The signature of the `process_routing` function changed in scikit-learn 1.4. You can
import the function from `sklearn_compat.utils.metadata_routing`. The pattern will
change from:
``` py
from sklearn.utils.metadata_routing import process_routing
class MetaEstimator(BaseEstimator):
def fit(self, X, y, sample_weight=None, **fit_params):
params = process_routing(self, "fit", fit_params, sample_weight=sample_weight)
return self
```
becomes:
``` py
from sklearn_compat.utils.metadata_routing import process_routing
class MetaEstimator(BaseEstimator):
def fit(self, X, y, sample_weight=None, **fit_params):
params = process_routing(self, "fit", sample_weight=sample_weight, **fit_params)
return self
```
The `_raise_for_params` function was also introduced in scikit-learn 1.4. You can import
it from `sklearn_compat.utils.metadata_routing`.
``` py
from sklearn_compat.utils.metadata_routing import _raise_for_params
_raise_for_params(params, self, "fit")
```
#### Upgrading to scikit-learn 1.2
### Parameter validation
scikit-learn introduced a new way to validate parameters at `fit` time. The recommended
way to support this feature in scikit-learn 1.2+ is to inherit from
`sklearn.base.BaseEstimator` and decorate the `fit` method using the decorator
`sklearn.base._fit_context`. For functions, the decorator to use is
`sklearn.utils._param_validation.validate_params`.
We provide the function `sklearn_compat.base._fit_context` such that you can always
decorate the `fit` method of your estimator. Equivalently, you can use the function
`sklearn_compat.utils._param_validation.validate_params` to validate the parameters
of your function.
## Contributing
You can contribute to this package by:
- reporting an incompatibility with a scikit-learn version on the
[issue tracker](https://github.com/sklearn-compat/sklearn-compat/issues). We will
do our best to provide a compatibility layer.
- opening a [pull-request](https://github.com/sklearn-compat/sklearn-compat/pulls) to
add a compatibility layer that you encountered when writing your scikit-learn
compatible estimator.
Be aware that to be able to provide `sklearn-compat` as a vendorable package and a
dependency, all the changes are implemented in the
`src/sklearn_compat/_sklearn_compat.py` (indeed not the nicest experience). Then, we
need to import the changes made in this file in the submodules to use `sklearn-compat`
as a dependency.
Raw data
{
"_id": null,
"home_page": null,
"name": "sklearn-compat",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": null,
"author": null,
"author_email": "Guillaume Lemaitre <guillaume@probabl.ai>, Adrin Jalali <adrin.jalali@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/23/7e/c5b43911ca5813eadfe1fd3f0a5e97f4f23c5006fba935b1172f350b4d17/sklearn_compat-0.1.3.tar.gz",
"platform": null,
"description": "# Ease multi-version support for scikit-learn compatible library\n\n[](https://scientific-python.org/specs/spec-0000/)\n\n[](https://codecov.io/gh/sklearn-compat/sklearn-compat)\n[](https://img.shields.io/pypi/pyversions/sklearn-compat.svg)\n[](https://badge.fury.io/py/sklearn-compat.svg)\n\n`sklearn-compat` is a small Python package that help developer writing scikit-learn\ncompatible estimators to support multiple scikit-learn versions. Note that we provide\na vendorable version of this package in the `src/sklearn_compat/_sklearn_compat.py`\nfile if you do not want to depend on `sklearn-compat` as a package. The package is\navailable on [PyPI](https://pypi.org/project/sklearn-compat/) and on\n[conda-forge](https://anaconda.org/conda-forge/sklearn-compat).\n\nAs maintainers of third-party libraries depending on scikit-learn such as\n[`imbalanced-learn`](https://github.com/scikit-learn-contrib/imbalanced-learn),\n[`skrub`](https://github.com/skrub-data/skrub), or\n[`skops`](https://github.com/skops-dev/skops), we usually identified small breaking\nchanges on the \"private\" developer utilities of `scikit-learn`. Indeed, each of these\nthird-party libraries code the exact same utilities when it comes to support multiple\n`scikit-learn` versions. We therefore decided to factorize these utilities in a\ndedicated package that we update at each `scikit-learn` release.\n\nWhen it comes to support multiple `scikit-learn` versions, the initial plan as of\nDecember 2024 is to follow the [SPEC0](https://scientific-python.org/specs/spec-0000/)\nrecommendations. It means that this utility will support **at least** the `scikit-learn`\nversions up to 2 years or about 4 versions. The current version of `sklearn-compat`\nsupports `scikit-learn` >= 1.2.\n\n## How to adapt your scikit-learn code\n\nIn this section, we describe succinctly the changes you need to do to your code to\nsupport multiple `scikit-learn` versions using `sklearn-compat` as a package. If you\nuse the vendored version of `sklearn-compat`, all imports will be changed from:\n\n``` py\nfrom sklearn_compat.any_submodule import any_function\n```\n\nto\n\n``` py\nfrom path.to._sklearn_compat import any_function\n```\n\nwhere `_sklearn_compat` is the vendored version of `sklearn-compat` in your project.\n\n### Upgrading to scikit-learn 1.6\n\n#### `is_clusterer` function\n\nThe function `is_clusterer` has been added in `scikit-learn` 1.6. So we backport it\nsuch that you can have access to it in scikit-learn 1.2+. The pattern is the following:\n\n``` py\nfrom sklearn.cluster import KMeans\nfrom sklearn_compat.base import is_clusterer\n\nis_clusterer(KMeans())\n```\n\n#### `validate_data` function\n\nYour previous code could have looked like this:\n\n``` py\nclass MyEstimator(BaseEstimator):\n def fit(self, X, y=None):\n X = self._validate_data(X, force_all_finite=True)\n return self\n```\n\nThere is two major changes in scikit-learn 1.6:\n\n- `validate_data` has been moved to `sklearn.utils.validation`.\n- `force_all_finite` is deprecated in favor of the `ensure_all_finite` parameter.\n\nYou can now use the following code for backward compatibility:\n\n``` py\nfrom sklearn_compat.utils.validation import validate_data\n\nclass MyEstimator(BaseEstimator):\n def fit(self, X, y=None):\n X = validate_data(self, X=X, ensure_all_finite=True)\n return self\n```\n\n#### `check_array` and `check_X_y` functions\n\nThe parameter `force_all_finite` has been deprecated in favor of the `ensure_all_finite`\nparameter. You need to modify the call to the function to use the new parameter. So,\nthe change is the same as for `validate_data` and will look like this:\n\n``` py\nfrom sklearn.utils.validation import check_array, check_X_y\n\ncheck_array(X, force_all_finite=True)\ncheck_X_y(X, y, force_all_finite=True)\n```\n\nto:\n\n``` py\nfrom sklearn_compat.utils.validation import check_array, check_X_y\n\ncheck_array(X, ensure_all_finite=True)\ncheck_X_y(X, y, ensure_all_finite=True)\n```\n\n#### `_check_n_features` and `_check_feature_names` functions\n\nSimilarly to `validate_data`, these two functions have been moved to\n`sklearn.utils.validation` instead of being methods of the estimators. So the following\ncode:\n\n``` py\nclass MyEstimator(BaseEstimator):\n def fit(self, X, y=None):\n self._check_n_features(X, reset=True)\n self._check_feature_names(X, reset=True)\n return self\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils.validation import _check_n_features, _check_feature_names\n\nclass MyEstimator(BaseEstimator):\n def fit(self, X, y=None):\n _check_n_features(self, X, reset=True)\n _check_feature_names(self, X, reset=True)\n return self\n```\n\nNote that it is best to call `validate_data` with `skip_check_array=True` instead of\ncalling these private functions. See the section above regarding `validate_data`.\n\n#### `Tags`, `__sklearn_tags__` and estimator tags\n\nThe estimator tags infrastructure in scikit-learn 1.6 has changed. In order to be\ncompatible with multiple scikit-learn versions, your estimator should implement both\n`_more_tags` and `__sklearn_tags__`:\n\n``` py\nclass MyEstimator(BaseEstimator):\n def _more_tags(self):\n return {\"non_deterministic\": True, \"poor_score\": True}\n\n def __sklearn_tags__(self):\n tags = super().__sklearn_tags__()\n tags.non_deterministic = True\n tags.regressor_tags.poor_score = True\n return tags\n```\n\nIn order to get the tags of a given estimator, you can use the `get_tags` function:\n\n``` py\nfrom sklearn_compat.utils import get_tags\n\ntags = get_tags(MyEstimator())\n```\n\nWhich uses `sklearn.utils.get_tags` under the hood from scikit-learn 1.6+.\n\nIn case you want to extend the tags, you can inherit from the available tags:\n\n```py\nfrom sklearn_compat.utils._tags import Tags, InputTags\n\nclass MyInputTags(InputTags):\n dataframe: bool = False\n\nclass MyEstimator(BaseEstimator):\n def __sklearn_tags__(self):\n tags = super().__sklearn_tags__()\n tags.input_tags = MyInputTags(\n one_d_array=tags.input_tags.one_d_array,\n two_d_array=tags.input_tags.two_d_array,\n sparse=tags.input_tags.sparse,\n category=True,\n dataframe=True,\n string=tags.input_tags.string,\n dict=tags.input_tags.dict,\n positive_only=tags.input_tags.positive_only,\n allow_nan=tags.input_tags.allow_nan,\n pairwise=tags.input_tags.pairwise,\n )\n return tags\n```\n\n\n#### `check_estimator` and `parametrize_with_checks` functions\n\nThe new tags don't include a `_xfail_checks` tags, and instead, the tests which are\nexpected to fail are directly passed to the `check_estimator` and\n`parametrize_with_checks` functions. The two functions available in this package are\ncompatible with the new signature, and patch the estimator in older scikit-learn\nversions to include the expected failed checks in their tags so that you don't need\nto include them both in your tests and in your `_xfail_checks` old tags.\n\n\n``` py\nfrom sklearn_compat.utils.testing import parametrize_with_checks\nfrom mypackage.myestimator import MyEstimator1, MyEstimator2\n\nEXPECTED_FAILED_CHECKS = {\n \"MyEstimator1\": {\"check_name1\": \"reason1\", \"check_name2\": \"reason2\"},\n \"MyEstimator2\": {\"check_name3\": \"reason3\"},\n}\n\n@parametrize_with_checks([MyEstimator1(), MyEstimator2()],\n expected_failed_checks=lambda est: EXPECTED_FAILED_CHECKS.get(\n est.__class__.__name__, {}\n )\n)\ndef test_my_estimator(estimator, check):\n check(estimator)\n```\n\n### Upgrading to scikit-learn 1.5\n\nIn scikit-learn 1.5, many developer utilities have been moved to dedicated modules.\nWe provide a compatibility layer such that you don't have to check the version or try\nto import the utilities from different modules.\n\nIn the future, when supporting scikit-learn 1.6+, you will have to change the import\nfrom:\n\n``` py\nfrom sklearn_compat.utils._indexing import _safe_indexing\n```\n\nto\n\n``` py\nfrom sklearn.utils._indexing import _safe_indexing\n```\n\nThus, the module path will already be correct. Now, we will go into details for\neach module and function impacted.\n\n#### `extmath` module\n\nThe function `safe_sqr` and `_approximate_mode` have been moved from `sklearn.utils` to\n`sklearn.utils.extmath`.\n\nSo some code looking like this:\n\n``` py\nfrom sklearn.utils import safe_sqr, _approximate_mode\n\nsafe_sqr(np.array([1, 2, 3]))\n_approximate_mode(class_counts=np.array([4, 2]), n_draws=3, rng=0)\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils.extmath import safe_sqr, _approximate_mode\n\nsafe_sqr(np.array([1, 2, 3]))\n_approximate_mode(class_counts=np.array([4, 2]), n_draws=3, rng=0)\n```\n\n#### `type_of_target` function\n\nThe function `type_of_target` accepts a new parameter `raise_unknown`. This parameter is\navailable in the `sklearn_compat.utils.multiclass.type_of_target` function.\n\n```py\nfrom sklearn_compat.utils.multiclass import type_of_target\n\ny = []\n# raise an error with unknown target type\ntype_of_target(y, raise_unknown=True)\n```\n\n#### `fixes` module\n\nThe functions `_in_unstable_openblas_configuration`, `_IS_32BIT` and `_IS_WASM` have\nbeen moved from `sklearn.utils` to `sklearn.utils.fixes`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import (\n _in_unstable_openblas_configuration,\n _IS_32BIT,\n _IS_WASM,\n)\n\n_in_unstable_openblas_configuration()\nprint(_IS_32BIT)\nprint(_IS_WASM)\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils.fixes import (\n _in_unstable_openblas_configuration,\n _IS_32BIT,\n _IS_WASM,\n)\n\n_in_unstable_openblas_configuration()\nprint(_IS_32BIT)\nprint(_IS_WASM)\n```\n\n#### `validation` module\n\nThe function `_to_object_array` has been moved from `sklearn.utils` to\n`sklearn.utils.validation`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import _to_object_array\n\n_to_object_array([np.array([0]), np.array([1])])\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils.validation import _to_object_array\n\n_to_object_array([np.array([0]), np.array([1])])\n```\n\n#### `_chunking` module\n\nThe functions `gen_batches`, `gen_even_slices` and `get_chunk_n_rows` have been moved\nfrom `sklearn.utils` to `sklearn.utils._chunking`. The function `chunk_generator` has\nbeen moved to `sklearn.utils._chunking` as well but was renamed from `_chunk_generator`\nto `chunk_generator`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import (\n _chunk_generator as chunk_generator,\n gen_batches,\n gen_even_slices,\n get_chunk_n_rows,\n)\n\n_chunk_generator(range(10), 3)\ngen_batches(7, 3)\ngen_even_slices(10, 1)\nget_chunk_n_rows(10)\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils._chunking import (\n chunk_generator, gen_batches, gen_even_slices, get_chunk_n_rows,\n)\n\nchunk_generator(range(10), 3)\ngen_batches(7, 3)\ngen_even_slices(10, 1)\nget_chunk_n_rows(10)\n```\n\n#### `_indexing` module\n\nThe utility functions `_determine_key_type`, `_safe_indexing`, `_safe_assign`,\n`_get_column_indices`, `resample` and `shuffle` have been moved from `sklearn.utils` to\n`sklearn.utils._indexing`.\n\nSo the following code:\n\n``` py\nimport numpy as np\nimport pandas as pd\nfrom sklearn.utils import (\n _get_column_indices,\n _safe_indexing,\n _safe_assign,\n resample,\n shuffle,\n)\n\n_determine_key_type(np.arange(10))\n\ndf = pd.DataFrame({\"a\": [1, 2, 3], \"b\": [4, 5, 6]})\n_get_column_indices(df, key=\"b\")\n_safe_indexing(df, 1, axis=1)\n_safe_assign(df, 1, np.array([7, 8, 9]))\n\narray = np.arange(10)\nresample(array, n_samples=20, replace=True, random_state=0)\nshuffle(array, random_state=0)\n```\n\nbecomes:\n\n``` py\nimport numpy as np\nimport pandas as pd\nfrom sklearn_compat.utils._indexing import (\n _determine_key_type,\n _safe_indexing,\n _safe_assign,\n _get_column_indices,\n resample,\n shuffle,\n)\n\n_determine_key_type(np.arange(10))\n\ndf = pd.DataFrame({\"a\": [1, 2, 3], \"b\": [4, 5, 6]})\n_get_column_indices(df, key=\"b\")\n_safe_indexing(df, 1, axis=1)\n_safe_assign(df, 1, np.array([7, 8, 9]))\n\narray = np.arange(10)\nresample(array, n_samples=20, replace=True, random_state=0)\nshuffle(array, random_state=0)\n```\n\n#### `_mask` module\n\nThe functions `safe_mask`, `axis0_safe_slice` and `indices_to_mask` have been moved from\n`sklearn.utils` to `sklearn.utils._mask`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import safe_mask, axis0_safe_slice, indices_to_mask\n\nsafe_mask(data, condition)\naxis0_safe_slice(X, mask, X.shape[0])\nindices_to_mask(indices, 5)\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils._mask import safe_mask, axis0_safe_slice, indices_to_mask\n\nsafe_mask(data, condition)\naxis0_safe_slice(X, mask, X.shape[0])\nindices_to_mask(indices, 5)\n```\n\n#### `_missing` module\n\nThe functions `is_scalar_nan` have been moved from `sklearn.utils` to\n`sklearn.utils._missing`. The function `_is_pandas_na` has been moved to\n`sklearn.utils._missing` as well and renamed to `is_pandas_na`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import is_scalar_nan, _is_pandas_na\n\nis_scalar_nan(float(\"nan\"))\n_is_pandas_na(float(\"nan\"))\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils._missing import is_scalar_nan, is_pandas_na\n\nis_scalar_nan(float(\"nan\"))\nis_pandas_na(float(\"nan\"))\n```\n\n#### `_user_interface` module\n\nThe function `_print_elapsed_time` has been moved from `sklearn.utils` to\n`sklearn.utils._user_interface`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import _print_elapsed_time\n\nwith _print_elapsed_time(\"sklearn_compat\", \"testing\"):\n time.sleep(0.1)\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils._user_interface import _print_elapsed_time\n\nwith _print_elapsed_time(\"sklearn_compat\", \"testing\"):\n time.sleep(0.1)\n```\n\n#### `_optional_dependencies` module\n\nThe functions `check_matplotlib_support` and `check_pandas_support` have been moved from\n`sklearn.utils` to `sklearn.utils._optional_dependencies`.\n\nSo the following code:\n\n``` py\nfrom sklearn.utils import check_matplotlib_support, check_pandas_support\n\ncheck_matplotlib_support(\"sklearn_compat\")\ncheck_pandas_support(\"sklearn_compat\")\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils._optional_dependencies import (\n check_matplotlib_support, check_pandas_support\n)\n\ncheck_matplotlib_support(\"sklearn_compat\")\ncheck_pandas_support(\"sklearn_compat\")\n```\n\n### Upgrading to scikit-learn 1.4\n\n#### `process_routing` and `_raise_for_params` functions\n\nThe signature of the `process_routing` function changed in scikit-learn 1.4. You can\nimport the function from `sklearn_compat.utils.metadata_routing`. The pattern will\nchange from:\n\n``` py\nfrom sklearn.utils.metadata_routing import process_routing\n\nclass MetaEstimator(BaseEstimator):\n def fit(self, X, y, sample_weight=None, **fit_params):\n params = process_routing(self, \"fit\", fit_params, sample_weight=sample_weight)\n return self\n```\n\nbecomes:\n\n``` py\nfrom sklearn_compat.utils.metadata_routing import process_routing\n\nclass MetaEstimator(BaseEstimator):\n def fit(self, X, y, sample_weight=None, **fit_params):\n params = process_routing(self, \"fit\", sample_weight=sample_weight, **fit_params)\n return self\n```\n\nThe `_raise_for_params` function was also introduced in scikit-learn 1.4. You can import\nit from `sklearn_compat.utils.metadata_routing`.\n\n``` py\nfrom sklearn_compat.utils.metadata_routing import _raise_for_params\n\n_raise_for_params(params, self, \"fit\")\n```\n\n#### Upgrading to scikit-learn 1.2\n\n### Parameter validation\n\nscikit-learn introduced a new way to validate parameters at `fit` time. The recommended\nway to support this feature in scikit-learn 1.2+ is to inherit from\n`sklearn.base.BaseEstimator` and decorate the `fit` method using the decorator\n`sklearn.base._fit_context`. For functions, the decorator to use is\n`sklearn.utils._param_validation.validate_params`.\n\nWe provide the function `sklearn_compat.base._fit_context` such that you can always\ndecorate the `fit` method of your estimator. Equivalently, you can use the function\n`sklearn_compat.utils._param_validation.validate_params` to validate the parameters\nof your function.\n\n## Contributing\n\nYou can contribute to this package by:\n\n- reporting an incompatibility with a scikit-learn version on the\n [issue tracker](https://github.com/sklearn-compat/sklearn-compat/issues). We will\n do our best to provide a compatibility layer.\n- opening a [pull-request](https://github.com/sklearn-compat/sklearn-compat/pulls) to\n add a compatibility layer that you encountered when writing your scikit-learn\n compatible estimator.\n\nBe aware that to be able to provide `sklearn-compat` as a vendorable package and a\ndependency, all the changes are implemented in the\n`src/sklearn_compat/_sklearn_compat.py` (indeed not the nicest experience). Then, we\nneed to import the changes made in this file in the submodules to use `sklearn-compat`\nas a dependency.\n",
"bugtrack_url": null,
"license": null,
"summary": "Ease support for compatible scikit-learn estimators across versions",
"version": "0.1.3",
"project_urls": {
"Homepage": "https://sklearn-compat.readthedocs.io/en/",
"Issues": "https://github.com/sklearn-compat/sklearn-compat/issues",
"Source": "https://github.com/sklearn-compat/sklearn-compat"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f0a8ad69cf130fbd017660cdd64abbef3f28135d9e2e15fe3002e03c5be0ca38",
"md5": "660e5a7f3f3439e7b10cd1c50a6e5d36",
"sha256": "a8aaf8ef711988cbd63f187c5560b5f16b25df663aaa1d2d0e1291341d339f80"
},
"downloads": -1,
"filename": "sklearn_compat-0.1.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "660e5a7f3f3439e7b10cd1c50a6e5d36",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 18995,
"upload_time": "2024-12-21T14:29:04",
"upload_time_iso_8601": "2024-12-21T14:29:04.862871Z",
"url": "https://files.pythonhosted.org/packages/f0/a8/ad69cf130fbd017660cdd64abbef3f28135d9e2e15fe3002e03c5be0ca38/sklearn_compat-0.1.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "237ec5b43911ca5813eadfe1fd3f0a5e97f4f23c5006fba935b1172f350b4d17",
"md5": "15b825b11e6ce62abd961425dcc45844",
"sha256": "74f8267613249d599aa3a2f2503af32fa51bce0800b1b0b0a57b52354402454e"
},
"downloads": -1,
"filename": "sklearn_compat-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "15b825b11e6ce62abd961425dcc45844",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 65857,
"upload_time": "2024-12-21T14:29:06",
"upload_time_iso_8601": "2024-12-21T14:29:06.240515Z",
"url": "https://files.pythonhosted.org/packages/23/7e/c5b43911ca5813eadfe1fd3f0a5e97f4f23c5006fba935b1172f350b4d17/sklearn_compat-0.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-21 14:29:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "sklearn-compat",
"github_project": "sklearn-compat",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "sklearn-compat"
}