Repository: sktime/sktime

Issue:
[BUG] `ConformalIntervals` `update` fails when `sample_frac` is not None
**Describe the bug**
`ConformalIntervals` `update` fails with an `IndexError` when `sample_frac` is not None because the overlapping index is not consistent between iterations (i.e. when doing `evaluate`).

**To Reproduce**

```python
from sktime.forecasting.conformal import ConformalIntervals
from sktime.forecasting.naive import NaiveForecaster
from sktime.datasets import load_airline
from sktime.forecasting.model_selection import SlidingWindowSplitter
from sktime.forecasting.model_evaluation import evaluate
from sktime.performance_metrics.forecasting.probabilistic import PinballLoss

y = load_airline()

cv = SlidingWindowSplitter(
        fh=np.arange(1, 13),
        window_length=48,
        step_length=12,
    )

f = NaiveForecaster()

interval_forecaster = ConformalIntervals(f, initial_window=24, sample_frac=0.2)

results = evaluate(
    forecaster=interval_forecaster,
    cv=cv,
    y=y,
    X=None,
    strategy="update",
    scoring=PinballLoss(alpha=[0.1, 0.5, 0.9]),
    return_data=True,
    error_score="raise",
    backend=None,
)
```

**Expected behavior**

If `sample_frac` is not None then the residuals matrix should just be recalculated for update (rather than extended). 

**Additional context**
<!--
Add any other context about the problem here.
-->

**Versions**
<details>

System:
    python: 3.8.13 (default, May  8 2022, 17:48:02)  [Clang 13.1.6 (clang-1316.0.21.2)]
executable: /Users/bethrice/Documents/Code/uk-ds-day-ahead-prices-forecast/.venv/bin/python
   machine: macOS-12.1-arm64-i386-64bit

Python dependencies:
          pip: 22.1.2
   setuptools: 63.1.0
      sklearn: 1.1.2
       sktime: 0.15.0
  statsmodels: 0.13.2
        numpy: 1.22.0
        scipy: 1.8.1
       pandas: 1.4.1
   matplotlib: 3.6.0
       joblib: 1.2.0
        numba: 0.56.2
     pmdarima: None
      tsfresh: None

</details>

<!-- Thanks for contributing! -->



Discussion:

Resolving patch:
diff --git a/sktime/forecasting/conformal.py b/sktime/forecasting/conformal.py
--- a/sktime/forecasting/conformal.py
+++ b/sktime/forecasting/conformal.py
@@ -377,7 +377,7 @@ def _compute_sliding_residuals(
             columns=full_y_index, index=full_y_index, dtype="float"
         )
 
-        if update and hasattr(self, "residuals_matrix_"):
+        if update and hasattr(self, "residuals_matrix_") and not sample_frac:
             remaining_y_index = full_y_index.difference(self.residuals_matrix_.index)
             if len(remaining_y_index) != len(full_y_index):
                 overlapping_index = pd.Index(


Test patch:
diff --git a/sktime/forecasting/tests/test_interval_wrappers.py b/sktime/forecasting/tests/test_interval_wrappers.py
--- a/sktime/forecasting/tests/test_interval_wrappers.py
+++ b/sktime/forecasting/tests/test_interval_wrappers.py
@@ -22,6 +22,7 @@
 INTERVAL_WRAPPERS = [ConformalIntervals, NaiveVariance]
 CV_SPLITTERS = [SlidingWindowSplitter, ExpandingWindowSplitter]
 EVALUATE_STRATEGY = ["update", "refit"]
+SAMPLE_FRACS = [None, 0.5]
 MTYPES_SERIES = scitype_to_mtype("Series", softdeps="present")
 
 
@@ -65,7 +66,8 @@ def test_wrapper_series_mtype(wrapper, override_y_mtype, mtype):
 @pytest.mark.parametrize("wrapper", INTERVAL_WRAPPERS)
 @pytest.mark.parametrize("splitter", CV_SPLITTERS)
 @pytest.mark.parametrize("strategy", EVALUATE_STRATEGY)
-def test_evaluate_with_window_splitters(wrapper, splitter, strategy):
+@pytest.mark.parametrize("sample_frac", SAMPLE_FRACS)
+def test_evaluate_with_window_splitters(wrapper, splitter, strategy, sample_frac):
     """Test interval wrappers with different strategies and cross validators.
 
     The wrapper does some internal sliding window cross-validation to
@@ -92,7 +94,10 @@ def test_evaluate_with_window_splitters(wrapper, splitter, strategy):
 
     f = NaiveForecaster()
 
-    interval_forecaster = wrapper(f, initial_window=24)
+    if wrapper == ConformalIntervals:
+        interval_forecaster = wrapper(f, initial_window=24, sample_frac=sample_frac)
+    else:
+        interval_forecaster = wrapper(f, initial_window=24)
 
     results = evaluate(
         forecaster=interval_forecaster,