Repository: sktime/sktime

Issue:
[BUG] NaiveForecaster  with strategy "mean" or "drift" returns NaN when forecasting horizon includes training dates
**Describe the bug**
NaiveForecaster forecasts "nan" if forecasting horizon includes training dates when strategy is  "drift" or "mean". If the strategy is "last", it works as expected.

The bug is in  [_BaseWindowForecaster _predict method](https://github.com/sktime/sktime/blob/32493231800d94f8a5b6df6d1bc42ae0fb398c69/sktime/forecasting/base/_sktime.py#L44).  It seems that the `y_oos` object is a pd.Series and `y_ins` is a pd.DataFrame. When concatenating, a dataframe with two columns is created, and one of them is dropped afterwards. Adding the code below right before pd.concat may fix the bug:

```python
if isinstance(y_ins, pd.DataFrame) and isinstance(y_oos, pd.Series):
                y_oos = y_oos.to_frame(y_ins.columns[0])
```

**To Reproduce**

```python
import numpy as np
import pandas as pd
from sktime.forecasting.naive import NaiveForecaster

n = 20
df = pd.DataFrame(
    index=pd.period_range("2020-01-01", periods=n, freq="D"),
    data={"value" : np.arange(n)})


model = NaiveForecaster(strategy="mean", window_length=7)
model.fit(df)
assert (model.predict(fh=[1,2,3]).values == [16, 16, 16]).all()
try:
    output = model.predict(fh=[0,1,2,3]).values.flatten() # output = [[15.],[nan], [nan], [nan]]
    assert (output == [15, 16, 16, 16]).all()
except AssertionError as e:
    print(output)

```

**Expected behavior**
NaiveForecaster should have returned [15, 16,16,16], but instead of "16" we obtain nan. 

**Versions**

System:
    python: 3.8.16 (default, Dec  7 2022, 01:36:11)  [Clang 14.0.0 (clang-1400.0.29.202)]
executable: [/Users/fangelim/Library/Caches/pypoetry/virtualenvs/app-y5Yj4LLu-py3.8/bin/python](https://file+.vscode-resource.vscode-cdn.net/Users/fangelim/Library/Caches/pypoetry/virtualenvs/app-y5Yj4LLu-py3.8/bin/python)
   machine: macOS-12.6.3-x86_64-i386-64bit

Python dependencies:
          pip: 23.1.2
       sktime: 0.19.1
      sklearn: 1.2.2
        numpy: 1.22.3
        scipy: 1.7.3
       pandas: 1.3.5
   matplotlib: 3.7.1
       joblib: 1.2.0
  statsmodels: 0.14.0
        numba: None
     pmdarima: 2.0.3
      tsfresh: None
   tensorflow: None
tensorflow_probability: None




Discussion:
Thanks for reporting!

The `NaiveForecaster` is such a patchwork of code that it might be worth just getting rid of `_BaseWindowForecaster` methods in it overall. I have started with a clean rewrite in `_predict_naive` after an earlier report that the `"last"` starategy was hopelessly slow.

We may look at further clean-up later on...

Until then it would be much appreciated if you could add your fix, and your code as a test case!
(test case should be in `sktime.forecasting.tests.test_naive`)

Let us know if you need any help with a PR; otherwise, we'll check your fix at some point in the next weeks, and add it if it works.
Reproduced on current `main`, python 3.11, windows.

PS, @felipeangelimvieira - I added missing imports in your code and fixed a syntax error. Should be copy-pasteable as a test now.
Thank you! I'll add the fix and create a PR during this week

Resolving patch:
diff --git a/sktime/forecasting/base/_sktime.py b/sktime/forecasting/base/_sktime.py
--- a/sktime/forecasting/base/_sktime.py
+++ b/sktime/forecasting/base/_sktime.py
@@ -41,6 +41,10 @@ def _predict(self, fh, X=None):
             y_oos = self._predict_fixed_cutoff(
                 fh.to_out_of_sample(self.cutoff), **kwargs
             )
+
+            if isinstance(y_ins, pd.DataFrame) and isinstance(y_oos, pd.Series):
+                y_oos = y_oos.to_frame(y_ins.columns[0])
+
             y_pred = pd.concat([y_ins, y_oos])
 
         # ensure pd.Series name attribute is preserved


Test patch:
diff --git a/sktime/forecasting/tests/test_window_forecasters.py b/sktime/forecasting/tests/test_window_forecasters.py
--- a/sktime/forecasting/tests/test_window_forecasters.py
+++ b/sktime/forecasting/tests/test_window_forecasters.py
@@ -5,10 +5,12 @@
 __author__ = ["mloning"]
 
 import numpy as np
+import pandas as pd
 import pytest
 
 from sktime.forecasting.base._sktime import _BaseWindowForecaster
 from sktime.forecasting.model_selection import temporal_train_test_split
+from sktime.forecasting.naive import NaiveForecaster
 from sktime.registry import all_estimators
 from sktime.utils._testing.forecasting import make_forecasting_problem
 from sktime.utils._testing.series import _make_series
@@ -42,3 +44,18 @@ def test_last_window(Forecaster):
 
     np.testing.assert_array_equal(actual, expected)
     assert len(actual) == f.window_length_
+
+
+def test_insample_and_outofsample_forecasting():
+    n = 20
+    df = pd.DataFrame(
+        index=pd.period_range("2020-01-01", periods=n, freq="D"),
+        data={"value": np.arange(n)},
+    )
+
+    model = NaiveForecaster(strategy="mean", window_length=7)
+    model.fit(df)
+
+    assert (model.predict(fh=[1, 2, 3]).values.flatten() == [16, 16, 16]).all()
+    assert (model.predict(fh=[0]).values.flatten() == [15]).all()
+    assert (model.predict(fh=[0, 1, 2, 3]).values.flatten() == [15, 16, 16, 16]).all()