Repository: sktime/sktime

Issue:
`MeanSquaredError` throws `FutureWarning` while passing `squared=True`
## Code

```python
>>> 
>>> from sktime.performance_metrics.forecasting import MeanSquaredError
>>> rmse = MeanSquaredError(square_root=True)
>>> 
>>> import numpy
>>> y_true = numpy.array([[0.5, 1], [-1, 1], [7, -6]])
>>> y_pred = numpy.array([[0, 2], [-1, 2], [8, -5]])
>>> 
>>> rmse(y_true, y_pred)
/home/anirban/conda-environments/sktime/lib/python3.10/site-packages/sklearn/metrics/_regression.py:483: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
  warnings.warn(
0.8227486121839513
>>> 
```

## Environment

Ubuntu WSL, python 3.10, sktime 0.26.0

## What to do

1. new dedicated metric for RMSE
2. if-else in the existing `mean_squared_error` function


Discussion:
2 is more deprecation safe, imo? `if not squared then np.sqrt`
I also prefer 2, but I actually meant in this sense. Both are probably identical, `sklearn` must be doing that.

```python
from sklearn.metrics import mean_squared_error as _mean_squared_error
from sklearn.metrics import root_mean_squared_error as _root_mean_squared_error

metric = _root_mean_squared_error if square_root else _mean_squared_error
return metric(y_true, y_pred, sample_weight=horizon_weight, multioutput=multioutput)
```
hm, I am slightly apprehensive since the architecture currently uses delegation with a fixed attribute being the metric, set in the class or constructor. So the `__init__` may have to do sth here.

Resolving patch:
diff --git a/sktime/performance_metrics/forecasting/_functions.py b/sktime/performance_metrics/forecasting/_functions.py
--- a/sktime/performance_metrics/forecasting/_functions.py
+++ b/sktime/performance_metrics/forecasting/_functions.py
@@ -8,6 +8,7 @@
 """
 
 import numpy as np
+import sklearn
 from scipy.stats import gmean
 from sklearn.metrics import mean_absolute_error as _mean_absolute_error
 from sklearn.metrics import mean_squared_error as _mean_squared_error
@@ -18,6 +19,9 @@
 
 from sktime.utils.stats import _weighted_geometric_mean
 
+if sklearn.__version__ >= "1.4.0":
+    from sklearn.metrics import root_mean_squared_error as _root_mean_squared_error
+
 __author__ = ["mloning", "tch", "RNKuhns"]
 __all__ = [
     "relative_loss",
@@ -998,18 +1002,24 @@ def mean_squared_error(
     >>> mean_squared_error(y_true, y_pred, multioutput=[0.3, 0.7], square_root=True)
     0.8936491673103708
     """
-    # Scikit-learn argument `squared` returns MSE when True and RMSE when False
-    # Scikit-time argument `square_root` returns RMSE when True and MSE when False
-    # Therefore need to pass the opposite of square_root as squared argument
-    # to the scikit-learn function being wrapped
-    squared = not square_root
-    return _mean_squared_error(
-        y_true,
-        y_pred,
-        sample_weight=horizon_weight,
-        multioutput=multioutput,
-        squared=squared,
-    )
+    metric_args = (y_true, y_pred)
+    metric_kwargs = {"sample_weight": horizon_weight, "multioutput": multioutput}
+
+    if not square_root:
+        metric_function = _mean_squared_error
+    elif sklearn.__version__ < "1.4.0":
+        # Scikit-learn argument `squared` returns MSE when True and RMSE when False
+        # Scikit-time argument `square_root` returns RMSE when True and MSE when False
+        # Therefore need to pass the opposite of square_root as squared argument
+        # to the scikit-learn function being wrapped
+        metric_function = _mean_squared_error
+        metric_kwargs["squared"] = False
+    else:
+        # sklearn 1.4 introduced ``root_mean_squared_error`` function, so we can
+        # use that directly to avoid DeprecationWarning from sklearn 1.6
+        metric_function = _root_mean_squared_error
+
+    return metric_function(*metric_args, **metric_kwargs)
 
 
 def median_absolute_error(


Test patch: