Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
60fbf22
init check_is_fitted mapie function
hmaissoro Nov 20, 2025
aed8170
add alias to sklearn check_is_fitted
hmaissoro Nov 20, 2025
ade9547
remore sklearn check_is_fitted func
hmaissoro Nov 20, 2025
ff7489c
remore sklearn check_is_fitted
hmaissoro Nov 20, 2025
c670d22
replace sk_leatn's check_is_fitted
hmaissoro Nov 20, 2025
b60f15e
remove sk_leatn's check_is_fitted
hmaissoro Nov 20, 2025
92100cc
replace sk_leatn's check_is_fitted
hmaissoro Nov 20, 2025
675b95b
remove sklearn dependence
hmaissoro Nov 20, 2025
29fae7a
use mapie check_is_fitted function
hmaissoro Nov 20, 2025
ea484b4
use mapie function
hmaissoro Nov 20, 2025
a908c70
replace by mapie function
hmaissoro Nov 20, 2025
e12a55a
reduce comment
hmaissoro Nov 20, 2025
b873640
add test
hmaissoro Nov 20, 2025
545809b
remove sklearn's check_is_fitted dependence
hmaissoro Nov 20, 2025
33c548e
update
hmaissoro Nov 20, 2025
0c31be1
more self._is_fitted bool
hmaissoro Nov 21, 2025
9d7431e
add is_fitted checking
hmaissoro Nov 21, 2025
f59d422
import mapie NotFittedError
hmaissoro Nov 21, 2025
cedfd6e
import sklearn's NotFittedError as sk_NotFittedError
hmaissoro Nov 21, 2025
ee51834
Update HISTORY.rst
hmaissoro Nov 21, 2025
c91d532
add docstring
hmaissoro Nov 21, 2025
6135b07
add docstring
hmaissoro Nov 21, 2025
d434c43
add docstring
hmaissoro Nov 21, 2025
08f183f
no cover
hmaissoro Nov 21, 2025
72a7e4d
Merge branch 'master' into user-xp/remove-check_is_fitted
hmaissoro Nov 25, 2025
0026e07
test is_fitted parameter directly
hmaissoro Nov 25, 2025
b24a45a
is_fitted is now covered
hmaissoro Nov 25, 2025
aa4f423
correct test
hmaissoro Nov 25, 2025
05b23be
user_model_check : add check function
hmaissoro Nov 25, 2025
5857eb1
user_model_check : add tests
hmaissoro Nov 25, 2025
ed1cfb3
replace sklearn's check_is_fitted
hmaissoro Nov 25, 2025
6b443eb
replace sklearn's check_is_fitted
hmaissoro Nov 25, 2025
49acf1a
replace sklearn's check_is_fitted
hmaissoro Nov 25, 2025
5d17fec
replace sklearn's check_is_fitted
hmaissoro Nov 25, 2025
cb19dad
add newline at end of file
hmaissoro Nov 26, 2025
e8fc5d0
accept two expectations
hmaissoro Nov 26, 2025
f9488bd
filter the warning since it is expected
hmaissoro Nov 26, 2025
d42ad5b
change implementation
hmaissoro Nov 26, 2025
bfb623e
update check_use_model_is_fitted's function is fitter
hmaissoro Nov 26, 2025
88d2bc8
filter expected warning and remove sklearn's NotFittedError dependence
hmaissoro Nov 26, 2025
24f7c53
remove unnecessary check_is_fitted
hmaissoro Nov 26, 2025
ac478f9
leave check_is_fitted in .predict methods because of tests
hmaissoro Nov 26, 2025
aa28ede
change regex
hmaissoro Nov 26, 2025
31527e6
add test for coverage
hmaissoro Nov 26, 2025
afa7904
formatting
hmaissoro Nov 26, 2025
82f8516
remove remaining sklearn's check_is_fitted dependence
hmaissoro Nov 27, 2025
a4176d4
remove sklearn's check_is_fitted
hmaissoro Nov 27, 2025
167661c
remove sklearn's check_is_fitted in tests
hmaissoro Nov 27, 2025
f32e3f6
remove sklearn's check_is_fitted
hmaissoro Nov 27, 2025
e187b96
update the docstring
hmaissoro Nov 27, 2025
433c83d
add sklearn in the name of check_user_model_is_fitted
hmaissoro Nov 27, 2025
e266f9c
update name
hmaissoro Nov 27, 2025
7cc2325
remove not covered ligne
hmaissoro Nov 27, 2025
a6e914c
remove unnecessary flag
hmaissoro Nov 28, 2025
47dc187
Raise warning instead of error
hmaissoro Nov 28, 2025
6fabe85
adjust flag usage
hmaissoro Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ History

1.x.x (2025-xx-xx)
------------------
* Remove dependency of internal classes on sklearn's check_is_fitted

1.2.0 (2025-11-17)
------------------
Expand Down
18 changes: 14 additions & 4 deletions mapie/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
from typing import Dict, Optional, Tuple, Union, cast

import numpy as np
from numpy.typing import ArrayLike, NDArray
from sklearn.base import BaseEstimator, ClassifierMixin, RegressorMixin, clone
from sklearn.calibration import _SigmoidCalibration
from sklearn.isotonic import IsotonicRegression
from sklearn.utils import check_random_state
from sklearn.utils.multiclass import type_of_target
from sklearn.utils.validation import _check_y, _num_samples, check_is_fitted, indexable
from sklearn.utils.validation import _check_y, _num_samples, indexable

from numpy.typing import ArrayLike, NDArray
from .utils import (
_check_estimator_classification,
_check_estimator_fit_predict,
_check_n_features_in,
_check_null_weight,
_fit_estimator,
_get_calib_set,
check_is_fitted,
)


Expand Down Expand Up @@ -123,6 +124,12 @@ def __init__(
self.estimator = estimator
self.calibrator = calibrator
self.cv = cv
self._is_fitted = False

@property
def is_fitted(self): # pragma: no cover
"""Returns True if the estimator is fitted"""
return self._is_fitted

def _check_cv(
self,
Expand Down Expand Up @@ -480,6 +487,9 @@ def fit(
self.calibrators = self._fit_calibrators(
X_calib, y_calib, sw_calib, calibrator
)

self._is_fitted = True

return self

def predict_proba(
Expand All @@ -501,7 +511,7 @@ def predict_proba(
The calibrated score for each max score and zeros at every
other position in that line.
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)
self.uncalib_pred = self.single_estimator_.predict_proba(X=X)

max_prob, y_pred = self._get_labels(X)
Expand Down Expand Up @@ -537,5 +547,5 @@ def predict(
NDArray of shape (n_samples,)
The class from the scores.
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)
return self.single_estimator_.predict(X)
38 changes: 20 additions & 18 deletions mapie/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,44 @@
from typing import Any, Iterable, Optional, Tuple, Union, cast

import numpy as np
from numpy.typing import ArrayLike, NDArray
from sklearn import clone
from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import (
BaseCrossValidator,
BaseShuffleSplit,
)
from sklearn.model_selection import BaseCrossValidator, BaseShuffleSplit
from sklearn.preprocessing import LabelEncoder
from sklearn.utils import check_random_state
from sklearn.utils.validation import _check_y, check_is_fitted, indexable

from numpy.typing import ArrayLike, NDArray
from sklearn.utils.validation import _check_y, indexable

from mapie.conformity_scores import BaseClassificationScore
from mapie.conformity_scores.sets.raps import RAPSConformityScore
from mapie.conformity_scores.utils import (
check_and_select_conformity_score,
check_classification_conformity_score,
check_target,
check_and_select_conformity_score,
)
from mapie.estimator.classifier import EnsembleClassifier
from mapie.utils import (
_cast_point_predictions_to_ndarray,
_cast_predictions_to_ndarray_tuple,
_check_alpha,
_check_alpha_and_n_samples,
_check_cv,
_check_cv_not_string,
_check_estimator_classification,
_check_n_features_in,
_check_n_jobs,
_check_null_weight,
_check_predict_params,
_check_verbose,
check_proba_normalized,
)
from mapie.utils import (
_transform_confidence_level_to_alpha_list,
_prepare_fit_params_and_sample_weight,
_prepare_params,
_raise_error_if_fit_called_in_prefit_mode,
_raise_error_if_method_already_called,
_prepare_params,
_raise_error_if_previous_method_not_called,
_cast_predictions_to_ndarray_tuple,
_cast_point_predictions_to_ndarray,
_check_cv_not_string,
_prepare_fit_params_and_sample_weight,
_transform_confidence_level_to_alpha_list,
check_is_fitted,
check_proba_normalized,
)


Expand Down Expand Up @@ -734,6 +729,12 @@ def __init__(
self.conformity_score = conformity_score
self.random_state = random_state
self.verbose = verbose
self._is_fitted = False

@property
def is_fitted(self): # pragma: no cover
"""Returns True if the estimator is fitted"""
return self._is_fitted

def _check_parameters(self) -> None:
"""
Expand Down Expand Up @@ -967,6 +968,7 @@ def fit(
groups=groups,
predict_params=predict_params,
)
self._is_fitted = True
return self

def predict(
Expand Down Expand Up @@ -1049,7 +1051,7 @@ def predict(
if hasattr(self, "_predict_params"):
_check_predict_params(self._predict_params, predict_params, self.cv)

check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)
alpha = cast(Optional[NDArray], _check_alpha(alpha))

# Estimate predictions
Expand Down
23 changes: 18 additions & 5 deletions mapie/estimator/classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@

import numpy as np
from joblib import Parallel, delayed
from numpy.typing import ArrayLike, NDArray
from sklearn.base import ClassifierMixin, clone
from sklearn.model_selection import BaseCrossValidator, BaseShuffleSplit
from sklearn.utils import _safe_indexing
from sklearn.utils.validation import _num_samples, check_is_fitted
from sklearn.utils.validation import _num_samples

from numpy.typing import ArrayLike, NDArray
from mapie.utils import _check_no_agg_cv, _fit_estimator, _fix_number_of_classes
from mapie.utils import (
_check_no_agg_cv,
_fit_estimator,
_fix_number_of_classes,
check_is_fitted,
)


class EnsembleClassifier:
Expand Down Expand Up @@ -121,6 +126,12 @@ def __init__(
self.n_jobs = n_jobs
self.test_size = test_size
self.verbose = verbose
self._is_fitted = False

@property
def is_fitted(self): # pragma: no cover
"""Returns True if the estimator is fitted"""
return self._is_fitted

@staticmethod
def _fit_oof_estimator(
Expand Down Expand Up @@ -344,6 +355,8 @@ def fit(
self.estimators_ = estimators_
self.k_ = k_

self._is_fitted = True

return self

def predict_proba_calib(
Expand Down Expand Up @@ -381,7 +394,7 @@ def predict_proba_calib(
NDArray of shape (n_samples_test, 1)
The predictions.
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)

if self.cv == "prefit":
y_pred_proba = self.single_estimator_.predict_proba(X, **predict_params)
Expand Down Expand Up @@ -445,7 +458,7 @@ def predict_agg_proba(
Predictions of shape
(n_samples, n_classes)
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)

y_pred_proba_k = np.asarray(
Parallel(n_jobs=self.n_jobs, verbose=self.verbose)(
Expand Down
22 changes: 17 additions & 5 deletions mapie/estimator/regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@

import numpy as np
from joblib import Parallel, delayed
from numpy.typing import ArrayLike, NDArray
from sklearn.base import RegressorMixin, clone
from sklearn.model_selection import BaseCrossValidator
from sklearn.utils import _safe_indexing
from sklearn.utils.validation import _num_samples, check_is_fitted
from sklearn.utils.validation import _num_samples

from numpy.typing import ArrayLike, NDArray
from mapie.aggregation_functions import aggregate_all, phi2D
from mapie.utils import (
_check_nan_in_aposteriori_prediction,
_check_no_agg_cv,
_fit_estimator,
check_is_fitted,
)


Expand Down Expand Up @@ -169,6 +170,12 @@ def __init__(
self.n_jobs = n_jobs
self.test_size = test_size
self.verbose = verbose
self._is_fitted = False

@property
def is_fitted(self): # pragma: no cover
"""Returns True if the estimator is fitted"""
return self._is_fitted

@staticmethod
def _fit_oof_estimator(
Expand Down Expand Up @@ -353,7 +360,7 @@ def predict_calib(
NDArray of shape (n_samples_test, 1)
The predictions.
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)

if self.cv == "prefit":
y_pred = self.single_estimator_.predict(X)
Expand Down Expand Up @@ -400,7 +407,7 @@ def fit(
"""
Note to developer: this fit method has been broken down into
fit_single_estimator and fit_multi_estimators,
but we kept it so that EnsembleRegressor passes sklearn.check_is_fitted.
but we kept it for consistency with the public fit() API.
Prefer using fit_single_estimator and fit_multi_estimators.

Fit the base estimator under the ``single_estimator_`` attribute.
Expand Down Expand Up @@ -482,6 +489,8 @@ def fit_multi_estimators(

self.estimators_ = estimators

self._is_fitted = True

return self

def fit_single_estimator(
Expand Down Expand Up @@ -515,6 +524,9 @@ def fit_single_estimator(
)

self.single_estimator_ = single_estimator_

self._is_fitted = True

return self

def predict(
Expand Down Expand Up @@ -560,7 +572,7 @@ def predict(
- The multiple predictions for the lower bound of the intervals.
- The multiple predictions for the upper bound of the intervals.
"""
check_is_fitted(self, self.fit_attributes)
check_is_fitted(self)

y_pred = self.single_estimator_.predict(X, **predict_params)
if not return_multi_pred and not ensemble:
Expand Down
Loading
Loading