Skip to content

AttributeError: The following error was raised: 'EnsembleRegressor' object has no attribute '__sklearn_tags__' with the scikit-learn dev branch #775

@ogrisel

Description

@ogrisel

Describe the bug

The scikit-learn estimator tags API has changed since the 1.6 release, and the 1.8 release will remove support for the deprecated API.

Here is the doc for the new API:

https://scikit-learn.org/dev/developers/develop.html#estimator-tags

Concretely, this means that MAPIE will break when conformalizing scikit-learn 1.8 estimators:

To Reproduce

# %%
from mapie.regression import CrossConformalRegressor
from sklearn.datasets import make_regression
from sklearn.linear_model import Ridge


X, y = make_regression(random_state=42)
mapie = CrossConformalRegressor(Ridge())
mapie.fit_conformalize(X, y)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/code/scikit-learn/sklearn/utils/_tags.py:275, in get_tags(estimator)
    274 try:
--> 275     tags = estimator.__sklearn_tags__()
    276 except AttributeError as exc:

AttributeError: 'EnsembleRegressor' object has no attribute '__sklearn_tags__'

During handling of the above exception, another exception occurred:

AttributeError                            Traceback (most recent call last)
Cell In[2], line 9
      7 X, y = make_regression(random_state=42)
      8 mapie = CrossConformalRegressor(Ridge())
----> 9 mapie.fit_conformalize(X, y)

File ~/miniforge3/envs/dev/lib/python3.13/site-packages/mapie/regression/regression.py:479, in CrossConformalRegressor.fit_conformalize(self, X, y, groups, fit_params, predict_params)
    475 fit_params_, sample_weight = _prepare_fit_params_and_sample_weight(
    476     fit_params
    477 )
    478 self._predict_params = _prepare_params(predict_params)
--> 479 self._mapie_regressor.fit(
    480     X,
    481     y,
    482     sample_weight,
    483     groups,
    484     fit_params=fit_params_,
    485     predict_params=self._predict_params
    486 )
    488 self.is_fitted_and_conformalized = True
    489 return self

File ~/miniforge3/envs/dev/lib/python3.13/site-packages/mapie/regression/regression.py:1413, in _MapieRegressor.fit(self, X, y, sample_weight, groups, **kwargs)
   1408 X, y, sample_weight, groups = self.init_fit(
   1409     X, y, sample_weight, groups, **kwargs
   1410 )
   1412 self.fit_estimator(X, y, sample_weight, groups)
-> 1413 self.conformalize(X, y, sample_weight, groups, **kwargs)
   1415 return self

File ~/miniforge3/envs/dev/lib/python3.13/site-packages/mapie/regression/regression.py:1491, in _MapieRegressor.conformalize(self, X, y, sample_weight, groups, **kwargs)
   1482 self.estimator_.fit_multi_estimators(
   1483     X,
   1484     y,
   (...)   1487     **self._fit_params
   1488 )
   1490 # Predict on calibration data
-> 1491 y_pred = self.estimator_.predict_calib(
   1492         X, y=y, groups=groups, **predict_params
   1493 )
   1495 # Compute the conformity scores (manage jk-ab case)
   1496 self.conformity_scores_ = \
   1497     self.conformity_score_function_.get_conformity_scores(
   1498         y, y_pred, X=X
   1499     )

File ~/miniforge3/envs/dev/lib/python3.13/site-packages/mapie/estimator/regressor.py:367, in EnsembleRegressor.predict_calib(self, X, y, groups, **predict_params)
    333 def predict_calib(
    334     self,
    335     X: ArrayLike,
   (...)    338     **predict_params
    339 ) -> NDArray:
    340     """
    341     Perform predictions on X : the calibration set.
    342 
   (...)    365         The predictions.
    366     """
--> 367     check_is_fitted(self, self.fit_attributes)
    369     if self.cv == "prefit":
    370         y_pred = self.single_estimator_.predict(X)

File ~/code/scikit-learn/sklearn/utils/validation.py:1699, in check_is_fitted(estimator, attributes, msg, all_or_any)
   1696 if not hasattr(estimator, "fit"):
   1697     raise TypeError("%s is not an estimator instance." % (estimator))
-> 1699 tags = get_tags(estimator)
   1701 if not tags.requires_fit and attributes is None:
   1702     return

File ~/code/scikit-learn/sklearn/utils/_tags.py:283, in get_tags(estimator)
    276 except AttributeError as exc:
    277     if "object has no attribute '__sklearn_tags__'" in str(exc):
    278         # Happens when `__sklearn_tags__` is implemented by calling
    279         # `super().__sklearn_tags__()` but there is no `__sklearn_tags__`
    280         # method in the base class. Typically happens when only inheriting
    281         # from Mixins.
--> 283         raise AttributeError(
    284             f"The following error was raised: {exc}. It seems that "
    285             "there are no classes that implement `__sklearn_tags__` "
    286             "in the MRO and/or all classes in the MRO call "
    287             "`super().__sklearn_tags__()`. Make sure to inherit from "
    288             "`BaseEstimator` which implements `__sklearn_tags__` (or "
    289             "alternatively define `__sklearn_tags__` but we don't recommend "
    290             "this approach). Note that `BaseEstimator` needs to be on the "
    291             "right side of other Mixins in the inheritance order."
    292         )
    293     else:
    294         raise

AttributeError: The following error was raised: 'EnsembleRegressor' object has no attribute '__sklearn_tags__'. It seems that there are no classes that implement `__sklearn_tags__` in the MRO and/or all classes in the MRO call `super().__sklearn_tags__()`. Make sure to inherit from `BaseEstimator` which implements `__sklearn_tags__` (or alternatively define `__sklearn_tags__` but we don't recommend this approach). Note that `BaseEstimator` needs to be on the right side of other Mixins in the inheritance order.

Additional context

To be able to stay compatible with versions of the scikit-learn estimators tags API you might find the following tool helpful:

https://github.com/sklearn-compat/sklearn-compat/?tab=readme-ov-file#tags-__sklearn_tags__-and-estimator-tags

Metadata

Metadata

Assignees

No one assigned

    Labels

    BacklogThis has a good chance to be implemented at some point.RegressionRelated to regression (excluding time series)

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions