Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Adaptive Conformal Inference method for Time Series #341

Merged
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
237f8a6
Ajout ACI
Aug 8, 2023
21e8e80
FIX : Correction passages lint, type check.
Aug 11, 2023
96d47d0
FIX: fix type-check and add warning
thibaultcordier Aug 11, 2023
8647ec1
UPD: format code and update metainfo
thibaultcordier Aug 11, 2023
f6f171e
FIX: scikit-learn error
thibaultcordier Aug 11, 2023
1897b91
FIX: take account conformity score function
thibaultcordier Aug 11, 2023
e5e0400
FIX: redefine previous tests for beta optimization
thibaultcordier Aug 11, 2023
20b49e8
ajout metrics cwc
QMaphan Aug 21, 2023
0c18c9f
FIX: fix type-check
QMaphan Aug 22, 2023
ec0b07f
FIX: fix type check
QMaphan Aug 22, 2023
e13771d
FIX= fix test_metrics
QMaphan Aug 23, 2023
6b50c65
FIX: fix test_metrics
QMaphan Aug 23, 2023
34ff553
FIX: fix type_check
QMaphan Aug 23, 2023
35e620f
fix: correction erreur typing
QMaphan Aug 23, 2023
3db5ad2
FIX: fix static type and metrics
QMaphan Aug 24, 2023
24ae12c
FIX: fix linting
QMaphan Aug 24, 2023
21448bf
FIX: fix typing
QMaphan Aug 24, 2023
4bc21f8
FIX: pytest
QMaphan Aug 24, 2023
2f839e1
FIX: pytest
QMaphan Aug 24, 2023
f87c4e7
FIX: fix pytest
QMaphan Aug 24, 2023
69dbb27
FIX: pytest
QMaphan Aug 24, 2023
8894bf5
FIX: Pytest
QMaphan Aug 24, 2023
9cbe0f4
FIX: pytest
QMaphan Aug 24, 2023
06c41d5
FIX: correction coverage utils and test_metrics
QMaphan Aug 24, 2023
c97cf57
FIX: fix coverage test
QMaphan Aug 25, 2023
4b6e6b0
Apply suggestions from code review (clean code)
thibaultcordier Aug 29, 2023
38e6979
FIX: remove blank lines
thibaultcordier Aug 29, 2023
b410c1a
FIX: change reference value
thibaultcordier Aug 29, 2023
d04f987
TMP: add empty test for coverage
thibaultcordier Aug 29, 2023
11e6a4d
Merge remote-tracking branch 'origin/master' into 334-adaptive-confor…
thibaultcordier Aug 29, 2023
db56bbe
FIX: lint error
thibaultcordier Aug 29, 2023
ec823ac
FIX: adapt valid test with no return
thibaultcordier Aug 29, 2023
0112b86
FIX: convert pandas series to numpy array
thibaultcordier Aug 29, 2023
5739c07
FIX: use existing metrics instead of picp & pinaw
QMaphan Sep 13, 2023
f4722cf
Fix: lint
QMaphan Sep 13, 2023
fdc70b1
Fix: lint
QMaphan Sep 13, 2023
69416f4
Fix : Orignal Paper
QMaphan Sep 13, 2023
a606c8d
FIX: ACI aci function and tutorial
QMaphan Sep 26, 2023
8bb352c
Fix : Correct metrics cwc and exemple
QMaphan Sep 27, 2023
63354ae
FIX : Lint
QMaphan Sep 27, 2023
670f213
Fix : plot_ts-tutorial comment and plot
QMaphan Sep 27, 2023
389daa4
FIX: mypy "ndarray[Any, dtype[Any]]" has no attribute "values"
QMaphan Sep 27, 2023
d6aafaa
Merge branch 'master' into 334-adaptive-conformal-predictions-for-tim…
thibaultcordier Sep 27, 2023
327b05f
FIX: lint error after merging
thibaultcordier Sep 27, 2023
0e94e74
Fix: Doc error
QMaphan Sep 27, 2023
20720a3
Update examples/regression/2-advanced-analysis/plot-coverage-width-ba…
QMaphan Sep 29, 2023
0697a57
Update examples/regression/4-tutorials/plot_ts-tutorial.py
QMaphan Sep 29, 2023
602b300
Update examples/regression/4-tutorials/plot_ts-tutorial.py
QMaphan Sep 29, 2023
de003f8
Update mapie/metrics.py
QMaphan Sep 29, 2023
d932b17
Update mapie/metrics.py
QMaphan Sep 29, 2023
1abda74
Update mapie/tests/test_metrics.py
QMaphan Sep 29, 2023
453632e
Update mapie/tests/test_metrics.py
QMaphan Sep 29, 2023
2dded22
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
a3083ed
Update mapie/utils.py
QMaphan Sep 29, 2023
0987952
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
e6b3164
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
c5e96f8
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
143a908
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
0166740
Update mapie/regression/time_series_regression.py
QMaphan Sep 29, 2023
cf80033
FIX: remove math latex in docstring
Sep 29, 2023
a3eb38d
FIX: correction documentation
QMaphan Sep 29, 2023
51274ae
Merge branch '334-adaptive-conformal-predictions-for-time-series' of …
QMaphan Sep 29, 2023
444d4e6
FIX: test error correction, raise wrong TS attribute
QMaphan Sep 29, 2023
6b9b929
FIX: doc maths equation
QMaphan Oct 2, 2023
6c6cdd2
Update mapie/tests/test_time_series_regression.py
QMaphan Oct 2, 2023
23a8aff
Update mapie/regression/time_series_regression.py
QMaphan Oct 2, 2023
9fdfdbb
Update exoplanets.ipynb
QMaphan Oct 2, 2023
6923e4c
Update exoplanets.ipynb
QMaphan Oct 2, 2023
e06ff19
Update tutorial_multilabel_classification_precision.ipynb
QMaphan Oct 2, 2023
332faec
Update tutorial_multilabel_classification_precision.ipynb
QMaphan Oct 2, 2023
c35cca3
Update tutorial_multilabel_classification_precision.ipynb
QMaphan Oct 2, 2023
ba06fb8
Update tutorial_regression.ipynb
QMaphan Oct 2, 2023
7d1aba2
Update ts-changepoint.ipynb
QMaphan Oct 4, 2023
ed03d3d
FIx: Correction based on Louis Lacombe remark
QMaphan Oct 23, 2023
6114566
Fix: Last update CP to aci
QMaphan Oct 23, 2023
49dbfbf
FIX: Lint error
QMaphan Oct 24, 2023
99ea1b4
FIX: mypy error, and correct doc writing
QMaphan Oct 25, 2023
0a9896e
Fix: lint error
QMaphan Oct 25, 2023
73746e3
Merge branch 'master' into 334-adaptive-conformal-predictions-for-tim…
thibaultcordier Nov 10, 2023
6ce4d77
UPD: latex formula
Nov 10, 2023
8845539
FIX: remove problematic formula
Nov 10, 2023
a236b77
Merge branch 'numpy-version-patch' into 334-adaptive-conformal-predic…
Nov 13, 2023
504b75f
UPD: improve metric tests
Nov 13, 2023
6bebaad
FIX: better value error raise
Nov 13, 2023
64bf885
UPD: improve docstring
Nov 13, 2023
ab76b99
UPD: style of test
Nov 13, 2023
f259f4f
UPD: format code example
Nov 13, 2023
f6a6e1d
UPD: better docstring
Nov 13, 2023
721d676
FIX: change mu to 1-alpha
Nov 14, 2023
bd013b9
FIX: ssl default
Nov 14, 2023
8052192
UPD: remove large files and transform nb to py file
Nov 14, 2023
60e8138
FIX: typo in results
Nov 14, 2023
fb848d4
UPD: add a header docstring
Nov 14, 2023
379db90
FIX: lint error
Nov 14, 2023
0d529ec
UPDATE : Add training with steps notebook ACI Zaffran
Dec 11, 2023
6c00dcf
UPD: iterative training notebook ACI Zaffran
Dec 11, 2023
75cc0a0
DEL: deplicated notebook wrt existing python file
Dec 12, 2023
2a055ec
Merge branch 'master' into 334-adaptive-conformal-predictions-for-tim…
thibaultcordier Dec 21, 2023
6d4b75b
FIX: lint
thibaultcordier Dec 21, 2023
c0d4337
UPD: consolidate ACI + reproduce experimental results
thibaultcordier Dec 21, 2023
31ea28d
UPD: adapt the aci preprocess + add corresponding tests
Dec 21, 2023
1e1911f
FIX: hyperlinks
thibaultcordier Dec 21, 2023
4bf1da2
UPD: else condition in update
Dec 21, 2023
e8c2ba4
UPD: change gamma value error message
Dec 21, 2023
176bbaf
UPD: change name of alpha method
Dec 21, 2023
e83389d
UPD: docstring
Dec 21, 2023
fc0522f
UPD: modify the user warning with a better function call
Dec 21, 2023
5a1c3ab
UPD: add DeprecationWarning for partial_fit
thibaultcordier Dec 21, 2023
b4c3029
FIX: add warnings and better indent
Dec 21, 2023
a0587a0
FIX: remove useless parameter
Dec 21, 2023
765b23f
UPD: change docstring and section names
Dec 21, 2023
a2fbd3a
UPD: allow infinite prediction intervals to be produced in regressor …
Dec 21, 2023
505a500
UPD: ACI doctring
thibaultcordier Dec 22, 2023
6b56953
UPD: add plot compared results
Dec 22, 2023
e6e7529
FIX: shorter hyperlink
thibaultcordier Jan 3, 2024
116eb2d
FIX: remove hyperlink
thibaultcordier Jan 3, 2024
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
2 changes: 2 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ Contributors
* Daniel Herbst <[email protected]>
* Candice Moyet <[email protected]>
* Sofiane Ziane <[email protected]>
* Remi Colliaux <[email protected]>
* Arthur Phan <[email protected]>

To be continued ...
2 changes: 2 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ History
* Refactor MapieRegressor and ConformityScore to add the possibility to use X in ConformityScore.
* Separate the handling of the estimator from MapieRegressor into a new class called EnsembleEstimator.
* Fix an unfixed random state in one of the classification tests.
* Add a new method for MapieTimeSeriesRegressor called ACI
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved
* Add a new metric named CWC
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved

0.6.5 (2023-06-06)
------------------
Expand Down
252 changes: 252 additions & 0 deletions mapie/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,3 +737,255 @@ def hsic(
coef_hsic = np.sqrt(np.matrix.trace(hsic_mat, axis1=1, axis2=2))

return coef_hsic


thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved
def _picp(
y_true: ArrayLike,
y_pred_low: ArrayLike,
y_pred_up: ArrayLike
) -> float:
"""
Calculate the Prediction Interval Coverage Probability (PICP).

The Prediction Interval Coverage Probability (PICP) is a measure used to
estimate the fraction of true labels that lie within the prediction
intervals.

[5] Vilde Jensen, Filippo Maria Bianchi, Stian Norman Anfinsen (2022).
Ensemble Conformalized Quantile Regression for Probabilistic Time Series
Forecasting.
QMaphan marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
y_true : ArrayLike
Array of true labels.
y_pred_low : ArrayLike
Array of lower bounds of prediction intervals.
y_pred_up : ArrayLike
Array of upper bounds of prediction intervals.

Returns
-------
float
Prediction Interval Coverage Probability (PICP).

Notes
-----
The PICP is calculated as follows:
1. Determine the number of true labels that lie within the prediction
intervals.
This is done by counting the number of elements that satisfy both
conditions:
(y_true >= y_pred_low) and (y_true <= y_pred_up). Let this count be
'in_the_range'.
2. Calculate the coverage by dividing 'in_the_range' by the total number
of true labels.

Examples
--------
>>> y_true = [5, 7.5, 9.5, 10.5, 12.5]
>>> y_pred_low = [4, 6, 9, 8.5, 10.5]
>>> y_pred_up = [6, 9, 10, 12.5, 12]
>>> y_true = np.array(y_true)
>>> y_pred_low = np.array(y_pred_low)
>>> y_pred_up = np.array(y_pred_up)
>>> print(_picp(y_true, y_pred_low, y_pred_up))
0.8
"""

# Ensure inputs are NumPy arrays for consistent operations
y_true = np.asarray(y_true)
y_pred_low = np.asarray(y_pred_low)
y_pred_up = np.asarray(y_pred_up)
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved

in_the_range = np.sum((np.greater_equal(y_true, y_pred_low))
& (np.less_equal(y_true, y_pred_up)))

coverage = in_the_range / np.prod(y_true.shape)

return float(coverage)


def _pinaw(
y_true: ArrayLike,
y_pred_low: ArrayLike,
y_pred_up: ArrayLike
) -> float:
"""
Calculate the Prediction Interval Normalized Average Width (PINAW).

The Prediction Interval Normalized Average Width (PINAW) is a measure
used to evaluate the average width of prediction intervals (PIs) in
relation to the range of the true labels.


[5] Vilde Jensen, Filippo Maria Bianchi, Stian Norman Anfinsen (2022).
Ensemble Conformalized Quantile Regression for Probabilistic Time Series
Forecasting.
QMaphan marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
y_true : ArrayLike
Array of true labels.
y_pred_low : ArrayLike
Array of lower bounds of prediction intervals.
y_pred_up : ArrayLike
Array of upper bounds of prediction intervals.

Returns
-------
float
Prediction Interval Normalized Average Width (PINAW).

Notes
-----
The PINAW is calculated as follows:
1. Calculate the average width of prediction intervals by taking the mean
of the absolute differences between the upper and lower bounds:
avg_length.
2. Normalize avg_length by dividing it by the range of the true labels:
(y_true.max() - y_true.min()).
3. The resulting value is the PINAW.

Examples
--------
>>> y_true = [5, 7.5, 9.5, 10.5, 12.5]
>>> y_pred_low = [4, 6, 9, 8.5, 10.5]
>>> y_pred_up = [6, 9, 10, 12.5, 12]
>>> y_true = np.array(y_true)
>>> y_pred_low = np.array(y_pred_low)
>>> y_pred_up = np.array(y_pred_up)
>>> print(np.round(_pinaw(y_true, y_pred_low, y_pred_up),2))
0.31
"""
# Convert y_true to a NumPy array of floats
y_true = np.array(y_true, dtype=float)
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved

avg_length = np.mean(np.abs(np.subtract(y_pred_up, y_pred_low)))
avg_length = avg_length / (np.subtract(float(y_true.max()),
float(y_true.min())))
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved

return float(avg_length)


def cwc(
y_true: ArrayLike,
y_pred_low: ArrayLike,
y_pred_up: ArrayLike,
eta: float,
mu: float
) -> float:
"""
Coverage width-based criterion obtained by the prediction intervals.
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved

The effective coverage score is a criterion used to evaluate the quality
of prediction intervals (PIs) based on their coverage and width.


[5] Vilde Jensen, Filippo Maria Bianchi, Stian Norman Anfinsen (2022).
Ensemble Conformalized Quantile Regression for Probabilistic Time Series
Forecasting.
QMaphan marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
picp : float
Prediction interval coverage probability (PICP), which is the estimated
fraction of true labels that lie within the prediction intervals.
pinaw : float
Prediction interval normalized average width (PINAW), calculated as
the average width of the prediction intervals.
QMaphan marked this conversation as resolved.
Show resolved Hide resolved
eta : int
A user-defined parameter that balances the contributions of PINAW and
PICP
in the coverage width-based criterion (CWC) calculation.
thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved
mu : float
A user-defined parameter representing the designed confidence level of
the PI.

Returns
-------
float
Effective coverage score (CWC) obtained by the prediction intervals.

Notes
-----
The effective coverage score (CWC) is calculated using the following
formula:
CWC = (1 - PINAW) * exp(-eta * (PICP - mu)**2)

The CWC penalizes under- and overcoverage in the same way and summarizes
the quality of the prediction intervals in a single value.

High Eta (Large Positive Value):

When eta is a high positive value, such as 10 or 100, it will strongly
emphasize the contribution of (1-pinaw). This means that the algorithm
will prioritize reducing the average width of the prediction intervals
(pinaw) over achieving a high coverage probability (picp).
The exponential term np.exp(-eta*(picp-mu)**2) will have a sharp decline
as picp deviates from mu. So, achieving a high picp becomes less important
compared to minimizing pinaw.
The impact will be narrower prediction intervals on average, which may
result in more precise but less conservative predictions.

Low Eta (Small Positive Value):

When eta is a low positive value, such as 0.01 or 0.1, it will still
prioritize reducing the average width of the prediction intervals (pinaw)
but with less emphasis compared to higher eta values.
The exponential term will be less steep, meaning that deviations of picp
from mu will have a moderate impact.
You'll get a balance between prediction precision and coverage, but the
exact balance will depend on the specific value of eta.

Negative Eta (Any Negative Value):

When eta is negative, it will have a different effect on the formula.
Negative values of eta will cause the exponential term
np.exp(-eta*(picp-mu)**2)
to become larger as picp deviates from mu. This means that a negative eta
prioritizes achieving a high coverage probability (picp) over minimizing
pinaw.
In this case, the algorithm will aim to produce wider prediction intervals
to ensure a higher likelihood of capturing the true values within those
intervals, even if it sacrifices precision.
Negative eta values might be used in scenarios where avoiding errors or
outliers is critical.

Null Eta (Eta = 0):

When eta is exactly zero, both pinaw and picp will have equal importance,
QMaphan marked this conversation as resolved.
Show resolved Hide resolved
as the exponential term becomes 1. This means there is a balance
between minimizing the average width of prediction intervals (pinaw)
and achieving a high coverage probability (picp).
The algorithm will aim for a trade-off between precision and coverage,
without giving preference to either one.
In summary, the choice of eta determines how much importance you place on
pinaw versus picp in your coverage width-based criterion.

A high eta emphasizes precision, a low positive eta balances precision
and coverage, a negative eta prioritizes coverage,
and a null eta equally values both precision and coverage.
The specific choice of eta should align with your objectives and the
trade-offs that are acceptable in your particular application.

Examples
--------
>>> y_true = np.array([5, 7.5, 9.5, 10.5, 12.5])
>>> y_preds_low = np.array([4, 6, 9, 8.5, 10.5])
>>> y_preds_up = np.array([6, 9, 10, 12.5, 12])
>>> eta = 30
>>> mu = 0.9
>>> print(np.round(cwc(y_true, y_preds_low, y_preds_up, eta, mu),2))
0.51
"""

thibaultcordier marked this conversation as resolved.
Show resolved Hide resolved
if 0 <= mu <= 1:
# Mu is within the valid range
picp = _picp(y_true, y_pred_low, y_pred_up)
pinaw = _pinaw(y_true, y_pred_low, y_pred_up)
cwc = (1-pinaw)*np.exp(-eta*(picp-mu)**2)

return float(cwc)
else:
raise ValueError("mu must be between 0 and 1")
Loading