Skip to content

Commit f6a7be0

Browse files
authored
refactor : rename partial_fit as internal method of TimeSeriesRegressor and update tests and docs (#792)
* rename partial_fit as internal method of TimeSeriesRegressor * update tests and doc * add author
1 parent c54ef60 commit f6a7be0

File tree

4 files changed

+36
-46
lines changed

4 files changed

+36
-46
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Development Lead
88
* Vincent Blot <[email protected]>
99
* Valentin Laurent <[email protected]>
1010
* Adrien Le Coz <[email protected]>
11+
* Hassan Maissoro <[email protected]>
1112
* Geoffray Brelurut <[email protected]>
1213

1314
Emeritus Core Developers

examples/regression/1-quickstart/plot_ts-tutorial.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class that block bootstraps the training set.
4343
each time new observations are available so that the deterioration of
4444
predictions, or the increase of noise level, can be dynamically taken into
4545
account. It can be done with :class:`~mapie.regression.TimeSeriesRegressor`
46-
through the ``partial_fit`` class method called at every step.
46+
through the ``update`` class method called at every step.
4747
4848
4949
The ACI strategy allows you to adapt the conformal inference
@@ -64,9 +64,9 @@ class that block bootstraps the training set.
6464
from sklearn.model_selection import RandomizedSearchCV, TimeSeriesSplit
6565

6666
from mapie.metrics.regression import (
67+
coverage_width_based,
6768
regression_coverage_score,
6869
regression_mean_width_score,
69-
coverage_width_based,
7070
)
7171
from mapie.regression import TimeSeriesRegressor
7272
from mapie.subsample import BlockBootstrap
@@ -178,11 +178,11 @@ class that block bootstraps the training set.
178178
# - with a regular ``.fit`` and ``.predict`` process, limiting the use of
179179
# trainining set residuals to build prediction intervals
180180
#
181-
# - using ``.partial_fit`` in addition to ``.fit`` and ``.predict`` allowing
181+
# - using ``.update`` in addition to ``.fit`` and ``.predict`` allowing
182182
# MAPIE to use new residuals from the test points as new data are becoming
183183
# available.
184184
#
185-
# - using ``.partial_fit`` and ``.adapt_conformal_inference`` in addition to
185+
# - using ``.update`` and ``.adapt_conformal_inference`` in addition to
186186
# ``.fit`` and ``.predict`` allowing MAPIE to use new residuals from the
187187
# test points as new data are becoming available.
188188
#
@@ -209,7 +209,7 @@ class that block bootstraps the training set.
209209

210210

211211
##############################################################################
212-
# Let's start by estimating prediction intervals without partial fit.
212+
# Let's start by estimating prediction intervals without partial update of the residuals.
213213

214214
# For EnbPI
215215
mapie_enbpi = mapie_enbpi.fit(X_train, y_train)
@@ -270,7 +270,7 @@ class that block bootstraps the training set.
270270

271271

272272
##############################################################################
273-
# Let's now estimate prediction intervals with partial fit. As discussed
273+
# Let's now estimate prediction intervals with updated residuals. As discussed
274274
# previously, the update of the residuals and the one-step ahead predictions
275275
# are performed sequentially in a loop.
276276

@@ -289,7 +289,7 @@ class that block bootstraps the training set.
289289
)
290290

291291
for step in range(gap, len(X_test), gap):
292-
mapie_enbpi.partial_fit(
292+
mapie_enbpi.update(
293293
X_test.iloc[(step - gap) : step, :],
294294
y_test.iloc[(step - gap) : step],
295295
)
@@ -336,9 +336,9 @@ class that block bootstraps the training set.
336336
)
337337

338338
for step in range(gap, len(X_test), gap):
339-
mapie_aci.partial_fit(
340-
X_test.iloc[(step - gap) : step, :],
341-
y_test.iloc[(step - gap) : step],
339+
mapie_aci.update(
340+
X_test.iloc[(step - gap) : step, :].to_numpy(),
341+
y_test.iloc[(step - gap) : step].to_numpy(),
342342
)
343343
mapie_aci.adapt_conformal_inference(
344344
X_test.iloc[(step - gap) : step, :].to_numpy(),
@@ -514,3 +514,5 @@ class that block bootstraps the training set.
514514
# One can notice that the uncertainty's explosion happens about one day late.
515515
# This is because enough new residuals are needed to change the quantiles
516516
# obtained from the residuals distribution.
517+
518+
# %%

mapie/regression/time_series_regression.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
from __future__ import annotations
22

3-
import warnings
43
from typing import Iterable, Optional, Tuple, Union, cast
54

65
import numpy as np
6+
from numpy.typing import ArrayLike, NDArray
77
from sklearn.base import RegressorMixin
88
from sklearn.model_selection import BaseCrossValidator
99
from sklearn.utils.validation import check_is_fitted
1010

11-
from numpy.typing import ArrayLike, NDArray
1211
from mapie.conformity_scores import BaseRegressionScore
1312
from mapie.regression.regression import _MapieRegressor
14-
from mapie.utils import _check_alpha, _check_gamma
15-
from mapie.utils import _transform_confidence_level_to_alpha_list
13+
from mapie.utils import (
14+
_check_alpha,
15+
_check_gamma,
16+
_transform_confidence_level_to_alpha_list,
17+
)
1618

1719

1820
class TimeSeriesRegressor(_MapieRegressor):
@@ -24,7 +26,7 @@ class TimeSeriesRegressor(_MapieRegressor):
2426
Both strategies are estimating prediction intervals
2527
on single-output time series.
2628
27-
EnbPI allows you to update conformal scores using the ``partial_fit``
29+
EnbPI allows you to update conformal scores using the ``update``
2830
function. It will replace the oldest one with the newest scores.
2931
It will keep the same amount of total scores
3032
@@ -118,7 +120,7 @@ def _relative_conformity_scores(
118120
)
119121
return scores
120122

121-
def partial_fit(
123+
def _update_conformity_scores_with_ensemble(
122124
self,
123125
X: ArrayLike,
124126
y: ArrayLike,
@@ -127,7 +129,7 @@ def partial_fit(
127129
"""
128130
Update the ``conformity_scores_`` attribute when new data with known
129131
labels are available.
130-
Note: Don't use ``partial_fit`` with samples of the training set.
132+
Note: Don't use ``_update_conformity_scores_with_ensemble`` with samples of the training set.
131133
132134
Parameters
133135
----------
@@ -159,13 +161,6 @@ def partial_fit(
159161
If the length of ``y`` is greater than
160162
the length of the training set.
161163
"""
162-
warnings.warn(
163-
"WARNING: Deprecated method. "
164-
+ 'The method "partial_fit" will be removed in v1.2. '
165-
+ 'Use "update" instead to keep '
166-
+ "the same behavior in the future.",
167-
DeprecationWarning,
168-
)
169164
check_is_fitted(self, self.fit_attributes)
170165
X, y = cast(NDArray, X), cast(NDArray, y)
171166
m, n = len(X), len(self.conformity_scores_)
@@ -330,8 +325,8 @@ def update(
330325
) -> TimeSeriesRegressor:
331326
"""
332327
Update with respect to the used ``method``.
333-
``method="enbpi"`` will call ``partial_fit`` method and
334-
``method="aci"`` will call ``adapt_conformal_inference`` method.
328+
``method="enbpi"`` updates conformity scores via EnbPI,
329+
``method="aci"`` calls ``adapt_conformal_inference``.
335330
336331
Parameters
337332
----------
@@ -381,7 +376,7 @@ def update(
381376
"""
382377
self._check_method(self.method)
383378
if self.method == "enbpi":
384-
return self.partial_fit(X, y, ensemble=ensemble)
379+
return self._update_conformity_scores_with_ensemble(X, y, ensemble=ensemble)
385380
elif self.method == "aci":
386381
return self.adapt_conformal_inference(
387382
X,

mapie/tests/test_time_series_regression.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,17 @@
44

55
import numpy as np
66
import pytest
7+
from numpy.typing import NDArray
78
from sklearn import __version__ as sklearn_version
89
from sklearn.datasets import make_regression
910
from sklearn.linear_model import LinearRegression
1011
from sklearn.model_selection import KFold, LeaveOneOut, train_test_split
1112
from sklearn.utils.estimator_checks import check_estimator
1213
from typing_extensions import TypedDict
1314

14-
from numpy.typing import NDArray
1515
from mapie.aggregation_functions import aggregate_all
1616
from mapie.conformity_scores import AbsoluteConformityScore
17-
from mapie.metrics.regression import (
18-
regression_coverage_score,
19-
)
17+
from mapie.metrics.regression import regression_coverage_score
2018
from mapie.regression import TimeSeriesRegressor
2119
from mapie.subsample import BlockBootstrap
2220

@@ -357,28 +355,30 @@ def test_MapieTimeSeriesRegressor_if_alpha_is_None() -> None:
357355
y_pred, y_pis = mapie_ts_reg.predict(X_toy, confidence_level=None)
358356

359357

360-
def test_MapieTimeSeriesRegressor_partial_fit_ensemble() -> None:
361-
"""Test ``partial_fit``."""
358+
def test_MapieTimeSeriesRegressor_update_conformity_scores_with_ensemble() -> None:
359+
"""Test ``_update_conformity_scores_with_ensemble``"""
362360
mapie_ts_reg = TimeSeriesRegressor(method="enbpi", cv=-1)
363361
mapie_ts_reg.fit(X_toy, y_toy)
364-
mapie_ts_reg.partial_fit(X_toy, y_toy, ensemble=True)
362+
mapie_ts_reg._update_conformity_scores_with_ensemble(X_toy, y_toy, ensemble=True)
365363
assert round(mapie_ts_reg.conformity_scores_[-1], 2) == round(
366364
np.abs(CONFORMITY_SCORES[0]), 2
367365
)
368-
mapie_ts_reg.partial_fit(
366+
mapie_ts_reg._update_conformity_scores_with_ensemble(
369367
X=np.array([UPDATE_DATA[0]]), y=np.array([UPDATE_DATA[1]]), ensemble=True
370368
)
371369
assert round(mapie_ts_reg.conformity_scores_[-1], 2) == round(
372370
CONFORMITY_SCORES[1], 2
373371
)
374372

375373

376-
def test_MapieTimeSeriesRegressor_partial_fit_too_big() -> None:
377-
"""Test ``partial_fit`` raised error."""
374+
def test_MapieTimeSeriesRegressor_update_conformity_scores_with_ensemble_too_big() -> (
375+
None
376+
):
377+
"""Test that ``_update_conformity_scores_with_ensemble`` raises an error."""
378378
mapie_ts_reg = TimeSeriesRegressor(method="enbpi", cv=-1)
379379
mapie_ts_reg.fit(X_toy, y_toy)
380380
with pytest.raises(ValueError, match=r".*The number of observations*"):
381-
mapie_ts_reg = mapie_ts_reg.partial_fit(X=X, y=y)
381+
mapie_ts_reg = mapie_ts_reg._update_conformity_scores_with_ensemble(X=X, y=y)
382382

383383

384384
def test_MapieTimeSeriesRegressor_beta_optimize_error() -> None:
@@ -458,14 +458,6 @@ def test_aci__get_alpha_with_unknown_alpha() -> None:
458458
np.testing.assert_allclose(mapie_ts_reg.current_alpha[0.2], 0.3, rtol=1e-3)
459459

460460

461-
def test_deprecated_partial_fit_warning() -> None:
462-
"""Test that a warning is raised if use partial_fit"""
463-
mapie_ts_reg = TimeSeriesRegressor(method="enbpi", cv=-1)
464-
mapie_ts_reg.fit(X_toy, y_toy)
465-
with pytest.warns(DeprecationWarning, match=r".*WARNING: Deprecated method.*"):
466-
mapie_ts_reg = mapie_ts_reg.partial_fit(X_toy, y_toy)
467-
468-
469461
@pytest.mark.parametrize("method", ["wrong_method"])
470462
def test_method_error_in_update(monkeypatch: Any, method: str) -> None:
471463
"""Test else condition for the method in .update"""

0 commit comments

Comments
 (0)