|
3 | 3 | Tutorial: Conditional CP for regression
|
4 | 4 | ============================================
|
5 | 5 |
|
6 |
| -We will use a synthetic toy dataset for the tutorial of the CCP method, and |
7 |
| -its comparison with the other methods available in MAPIE. The CCP method |
| 6 | +The tutorial will explain how to use the CCP method, and |
| 7 | +will compare it with the other methods available in MAPIE. The CCP method |
8 | 8 | implements the method described in the Gibbs et al. (2023) paper [1].
|
9 | 9 |
|
10 | 10 | We will see in this tutorial how to use the method. It has a lot of advantages:
|
11 | 11 |
|
12 | 12 | - It is model agnostic (it doesn't depend on the model but only on the
|
13 | 13 | predictions, unlike `CQR`)
|
14 |
| -- It uses the `split` approach (it require a calibration set, but is very fast |
15 |
| - at inference time, unlike the `CV` approach) |
16 | 14 | - It can create very adaptative intervals (with a varying width which truly
|
17 | 15 | eflects the model uncertainty)
|
18 | 16 | - while providing coverage guantee on all sub-groups of interest
|
|
24 | 22 | - The adaptativity depends on the calibrator we use: It can be difficult to
|
25 | 23 | choose the correct calibrator,
|
26 | 24 | with the best parameters (this tutorial will try to help you with this task).
|
27 |
| -- If the inference is very fast, the calibration phase can be very long, |
28 |
| - depending on the complexity of your calibrator |
| 25 | +- The calibration and even more the inference are much longer than for the |
| 26 | + other methods. We can reduce the inference time using |
| 27 | + ``unsafe_approximation=True``, but we lose the theoretical guarantees and |
| 28 | + risk a small miscoverage |
| 29 | + (even if, most of the time, the coverage is achieved). |
29 | 30 |
|
30 | 31 | Conclusion on the method:
|
31 | 32 |
|
|
35 | 36 |
|
36 | 37 | ----
|
37 | 38 |
|
38 |
| -In this tutorial, the estimator will be :class:`~sklearn.pipeline.Pipeline` |
| 39 | +In this tutorial, we will use a synthetic toy dataset. |
| 40 | +The estimator will be :class:`~sklearn.pipeline.Pipeline` |
39 | 41 | with :class:`~sklearn.preprocessing.PolynomialFeatures` and
|
40 | 42 | :class:`~sklearn.linear_model.LinearRegression` (or
|
41 | 43 | :class:`~sklearn.linear_model.QuantileRegressor` for CQR).
|
|
51 | 53 |
|
52 | 54 | Recall that the ``alpha`` is ``1 - target coverage``.
|
53 | 55 |
|
| 56 | +Warning: |
| 57 | +
|
| 58 | +In this tutorial, we use ``unsafe_approximation=True`` to have a faster |
| 59 | +computation (because Read The Docs examples require fast computation). |
| 60 | +This mode use an approximation, which make the inference (``predict``) faster, |
| 61 | +but induce a small miscoverage. It is recommanded not to use it, or be |
| 62 | +very careful and empirically check the coverage and a test set. |
| 63 | +
|
54 | 64 | [1] Isaac Gibbs, John J. Cherian, and Emmanuel J. Candès,
|
55 | 65 | "Conformal Prediction With Conditional Guarantees",
|
56 | 66 | `arXiv <https://arxiv.org/abs/2305.12616>`_, 2023.
|
|
78 | 88 | np.random.seed(random_state)
|
79 | 89 |
|
80 | 90 | ALPHA = 0.1
|
| 91 | +UNSAFE_APPROXIMATION = True |
81 | 92 |
|
82 | 93 | ##############################################################################
|
83 | 94 | # 1. Data generation
|
|
90 | 101 | # - between 0 and 5: normal distribution with a noise value which
|
91 | 102 | # increase with ``x``
|
92 | 103 | #
|
93 |
| -# We are going to use 3000 samples for training, 3000 for calibration and |
94 |
| -# 20 000 for testing (to have an accurate conditional coverage). |
| 104 | +# We are going to use 5000 samples for training, 5000 for calibration and |
| 105 | +# 5000 for testing. |
95 | 106 |
|
96 | 107 |
|
97 | 108 | def x_sinx(x):
|
@@ -123,7 +134,7 @@ def get_1d_data_with_heteroscedastic_noise(
|
123 | 134 | return X.reshape(-1, 1), y, true_pi
|
124 | 135 |
|
125 | 136 |
|
126 |
| -def generate_data(n_train=6000, n_test=20000, noise=0.8, power=2): |
| 137 | +def generate_data(n_train=10000, n_test=5000, noise=0.8, power=2): |
127 | 138 | X, y, true_pi = get_1d_data_with_heteroscedastic_noise(
|
128 | 139 | x_sinx, -1, 5, n_train + n_test, noise, power)
|
129 | 140 | indexes = list(range(len(X)))
|
@@ -428,7 +439,9 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
|
428 | 439 | mapie_ccp = SplitCPRegressor(estimator, calibrator=GaussianCCP(),
|
429 | 440 | alpha=ALPHA, cv=cv)
|
430 | 441 | mapie_ccp.fit(X_train, y_train)
|
431 |
| -y_pred_ccp, y_pi_ccp = mapie_ccp.predict(X_test) |
| 442 | +y_pred_ccp, y_pi_ccp = mapie_ccp.predict( |
| 443 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 444 | +) |
432 | 445 |
|
433 | 446 | # ================== PLOT ==================
|
434 | 447 | mapies = [mapie_split, mapie_cv, mapie_cqr, mapie_ccp]
|
@@ -533,19 +546,25 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
|
533 | 546 | mapie_ccp_1 = SplitCPRegressor(estimator, calibrator=calibrator_gauss1,
|
534 | 547 | cv=cv, alpha=ALPHA)
|
535 | 548 | mapie_ccp_1.fit(X_train, y_train)
|
536 |
| -y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(X_test) |
| 549 | +y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict( |
| 550 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 551 | +) |
537 | 552 |
|
538 | 553 | # # ================== CCP 2 ==================
|
539 | 554 | mapie_ccp_2 = SplitCPRegressor(estimator, calibrator=calibrator_gauss2,
|
540 | 555 | cv=cv, alpha=ALPHA)
|
541 | 556 | mapie_ccp_2.fit(X_train, y_train)
|
542 |
| -y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(X_test) |
| 557 | +y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict( |
| 558 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 559 | +) |
543 | 560 |
|
544 | 561 | # # ================== CCP 3 ==================
|
545 | 562 | mapie_ccp_3 = SplitCPRegressor(estimator, calibrator=calibrator_gauss3,
|
546 | 563 | cv=cv, alpha=ALPHA)
|
547 | 564 | mapie_ccp_3.fit(X_train, y_train)
|
548 |
| -y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(X_test) |
| 565 | +y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict( |
| 566 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 567 | +) |
549 | 568 |
|
550 | 569 |
|
551 | 570 | mapies = [mapie_split, mapie_cv, mapie_cqr,
|
@@ -605,19 +624,25 @@ def plot_evaluation(titles, y_pis, X_test, y_test):
|
605 | 624 | mapie_ccp_1 = SplitCPRegressor(estimator, calibrator=calibrator1,
|
606 | 625 | cv=cv, alpha=ALPHA)
|
607 | 626 | mapie_ccp_1.fit(X_train, y_train)
|
608 |
| -y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict(X_test) |
| 627 | +y_pred_ccp_1, y_pi_ccp_1 = mapie_ccp_1.predict( |
| 628 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 629 | +) |
609 | 630 |
|
610 | 631 | # ================== CCP 2 ==================
|
611 | 632 | mapie_ccp_2 = SplitCPRegressor(estimator, calibrator=calibrator2,
|
612 | 633 | cv=cv, alpha=ALPHA)
|
613 | 634 | mapie_ccp_2.fit(X_train, y_train)
|
614 |
| -y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict(X_test) |
| 635 | +y_pred_ccp_2, y_pi_ccp_2 = mapie_ccp_2.predict( |
| 636 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 637 | +) |
615 | 638 |
|
616 | 639 | # ================== CCP 3 ==================
|
617 | 640 | mapie_ccp_3 = SplitCPRegressor(estimator, calibrator=calibrator3,
|
618 | 641 | cv=cv, alpha=ALPHA)
|
619 | 642 | mapie_ccp_3.fit(X_train, y_train)
|
620 |
| -y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict(X_test) |
| 643 | +y_pred_ccp_3, y_pi_ccp_3 = mapie_ccp_3.predict( |
| 644 | + X_test, unsafe_approximation=UNSAFE_APPROXIMATION |
| 645 | +) |
621 | 646 |
|
622 | 647 | mapies = [mapie_split, mapie_cv, mapie_cqr,
|
623 | 648 | mapie_ccp_1, mapie_ccp_2, mapie_ccp_3]
|
|
0 commit comments