Repository: sktime/sktime
Pull request #6186 (2024-03-21 18:50:59)

[DOC] ExponentialSmoothing default method change from L-BFGS-B to SLSQP
#### Reference Issues/PRs
While exploring #6175, realized that the default parameter for `method` in Exponential Smoothing should be `SLSQP`. This also affects statsmodels documentation and there is already an [open PR](https://github.com/statsmodels/statsmodels/pull/9129) in their repo to fix this.

#### What does this implement/fix? Explain your changes.
Changes `method='L-BFGS-B'` to `method='SLSQP'`.

#### Does your contribution introduce a new dependency? If yes, which one?
No

#### What should a reviewer concentrate their feedback on?
See [statsmodels default](https://github.com/statsmodels/statsmodels/blob/192670b31c9069b247b0901d66013853e2ca47b7/statsmodels/tsa/holtwinters/model.py#L1142C1-L1142C55)

#### Did you add any tests for the change?
N/A

#### Any other comments?
N/A

#### PR checklist
<!--
Please go through the checklist below. Please feel free to remove points if they are not applicable.
-->

##### For all contributions
- [X] I've added myself to the [list of contributors](https://github.com/sktime/sktime/blob/main/CONTRIBUTORS.md) with any new badges I've earned :-)
  How to: add yourself to the [all-contributors file](https://github.com/sktime/sktime/blob/main/.all-contributorsrc) in the `sktime` root directory (not the `CONTRIBUTORS.md`). Common badges: `code` - fixing a bug, or adding code logic. `doc` - writing or improving documentation or docstrings. `bug` - reporting or diagnosing a bug (get this plus `code` if you also fixed the bug in the PR).`maintenance` - CI, test framework, release.
  See here for [full badge reference](https://allcontributors.org/docs/en/emoji-key)
- [ ] Optionally, I've added myself and possibly others to the [CODEOWNERS](https://github.com/sktime/sktime/blob/main/CODEOWNERS) file - do this if you want to become the owner or maintainer of an estimator you added.
  See here for further details on the [algorithm maintainer role](https://www.sktime.net/en/latest/get_involved/governance.html#algorithm-maintainers).
- [X] The PR title starts with either [ENH], [MNT], [DOC], or [BUG]. [BUG] - bugfix, [MNT] - CI, test framework, [ENH] - adding or improving code, [DOC] - writing or improving documentation or docstrings.



Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3e39feada..d44f41409 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2706,6 +2706,15 @@
       "contributions": [
         "doc"
       ]
+    },
+    {
+      "login": "manuel-munoz-aguirre",
+      "name": "Manuel Muñoz Aguirre",
+      "avatar_url": "https://avatars.githubusercontent.com/u/5576458?v=4",
+      "profile": "https://github.com/manuel-munoz-aguirre",
+      "contributions": [
+        "doc"
+      ]
     }
   ]
 }
diff --git a/docs/source/api_reference/forecasting.rst b/docs/source/api_reference/forecasting.rst
index d89ea3104..bcd8b1bbc 100644
--- a/docs/source/api_reference/forecasting.rst
+++ b/docs/source/api_reference/forecasting.rst
@@ -369,7 +369,7 @@ Deep learning based forecasters
     :toctree: auto_generated/
     :template: class.rst
 
-    CINNForecaster
+    cINNForecaster
 
 .. currentmodule:: sktime.forecasting.neuralforecast
 
diff --git a/sktime/forecasting/conditional_invertible_neural_network.py b/sktime/forecasting/conditional_invertible_neural_network.py
index a6279c761..cf66baaed 100644
--- a/sktime/forecasting/conditional_invertible_neural_network.py
+++ b/sktime/forecasting/conditional_invertible_neural_network.py
@@ -17,6 +17,7 @@ from sktime.networks.cinn import cINNNetwork
 from sktime.transformations.merger import Merger
 from sktime.transformations.series.fourier import FourierFeatures
 from sktime.transformations.series.summarize import WindowSummarizer
+from sktime.utils.warnings import warn
 
 if _check_soft_dependencies("torch", severity="none"):
     import torch
@@ -41,6 +42,7 @@ def default_sine(x, amplitude, phase, offset, amplitude2, amplitude3, phase2):
     return sbase + s1 + s2
 
 
+# TODO 0.29.0: rename the class cINNForecaster to CINNForecaster
 class cINNForecaster(BaseDeepNetworkPyTorch):
     """
     Conditional Invertible Neural Network (cINN) Forecaster.
@@ -177,6 +179,17 @@ class cINNForecaster(BaseDeepNetworkPyTorch):
         self.val_split = val_split
         super().__init__(num_epochs, batch_size, lr=lr)
 
+        warn(
+            "cINNForecaster will be renamed to CINNForecaster in sktime 0.29.0, "
+            "The estimator is available under the future name at its "
+            "current location, and will be available under its deprecated name "
+            "until 0.30.0. "
+            "To prepare for the name change, "
+            "replace cINNForecaster with CINNForecaster",
+            DeprecationWarning,
+            obj=self,
+        )
+
     def _fit(self, y, fh, X=None):
         """Fit forecaster to training data.
 
@@ -607,3 +620,8 @@ class _EarlyStopper:
             if self.counter >= self.patience:
                 return True
         return False
+
+
+# TODO 0.29.0: switch the line to cINNForecaster = CINNForecaster
+# TODO 0.30.0: remove this alias altogether
+CINNForecaster = cINNForecaster
diff --git a/sktime/forecasting/exp_smoothing.py b/sktime/forecasting/exp_smoothing.py
index 9cff4b5ef..9b5b2d1c5 100644
--- a/sktime/forecasting/exp_smoothing.py
+++ b/sktime/forecasting/exp_smoothing.py
@@ -70,7 +70,7 @@ class ExponentialSmoothing(_StatsModelsAdapter):
         starting values are determined using a combination of grid search
         and reasonable values based on the initial values of the data. See
         the notes for the structure of the model parameters.
-    method : str, default "L-BFGS-B"
+    method : str, default "SLSQP"
         The minimizer used. Valid options are "L-BFGS-B" , "TNC",
         "SLSQP" (default), "Powell", "trust-constr", "basinhopping" (also
         "bh") and "least_squares" (also "ls"). basinhopping tries multiple
diff --git a/sktime/networks/cinn.py b/sktime/networks/cinn.py
index 2b6be944f..c2438faf0 100644
--- a/sktime/networks/cinn.py
+++ b/sktime/networks/cinn.py
@@ -4,6 +4,8 @@ __author__ = ["benHeid"]
 import numpy as np
 from skbase.utils.dependencies import _check_soft_dependencies
 
+from sktime.utils.warnings import warn
+
 if _check_soft_dependencies("torch", severity="none"):
     import torch
     import torch.nn as nn
@@ -22,6 +24,7 @@ if _check_soft_dependencies("FrEIA", severity="none"):
     import FrEIA.modules as Fm
 
 
+# TODO 0.29.0: rename the class cINNNetwork to CINNNetwork
 class cINNNetwork:
     """
     Conditional Invertible Neural Network.
@@ -193,6 +196,17 @@ class cINNNetwork:
         self.hidden_dim_size = hidden_dim_size
         self.activation = activation if activation is not None else nn.ReLU
 
+        warn(
+            "cINNNetwork will be renamed to CINNNetwork in sktime 0.29.0, "
+            "The estimator is available under the future name at its "
+            "current location, and will be available under its deprecated name "
+            "until 0.30.0. "
+            "To prepare for the name change, "
+            "replace cINNNetwork with CINNNetwork",
+            DeprecationWarning,
+            obj=self,
+        )
+
     def build(self):
         """Build the cINN."""
         return self._cINNNetwork(
@@ -203,3 +217,8 @@ class cINNNetwork:
             self.hidden_dim_size,
             self.activation,
         )
+
+
+# TODO 0.29.0: switch the line to cINNNetwork = CINNNetwork
+# TODO 0.30.0: remove this alias altogether
+CINNNetwork = cINNNetwork
diff --git a/sktime/transformations/compose/_featureunion.py b/sktime/transformations/compose/_featureunion.py
index a461f574e..5151f1b2f 100644
--- a/sktime/transformations/compose/_featureunion.py
+++ b/sktime/transformations/compose/_featureunion.py
@@ -80,9 +80,10 @@ class FeatureUnion(_HeterogenousMetaEstimator, BaseTransformer):
         flatten_transform_index=True,
     ):
         self.transformer_list = transformer_list
-        self.transformer_list_ = self._check_estimators(
+        transformer_list_ = self._check_estimators(
             transformer_list, cls_type=BaseTransformer
         )
+        self.transformer_list_ = transformer_list_
 
         self.n_jobs = n_jobs
         self.transformer_weights = transformer_weights
@@ -90,9 +91,11 @@ class FeatureUnion(_HeterogenousMetaEstimator, BaseTransformer):
 
         super().__init__()
 
-        # todo: check for transform-input, transform-output
-        #   for now, we assume it's always Series/Series or Series/Panel
-        #   but no error is currently raised
+        t_outs = [t.get_tag("scitype:transform-output") for _, t in transformer_list_]
+        t_ins = [t.get_tag("scitype:transform-input") for _, t in transformer_list_]
+        # todo: error or special case handling if these are not all the same
+        self.set_tags(**{"scitype:transform-output": t_outs[0]})
+        self.set_tags(**{"scitype:transform-input": t_ins[0]})
 
         # abbreviate for readability
         ests = self.transformer_list_


Test patch:
diff --git a/sktime/transformations/tests/test_compose.py b/sktime/transformations/tests/test_compose.py
index 0b64a605b..f06a0377c 100644
--- a/sktime/transformations/tests/test_compose.py
+++ b/sktime/transformations/tests/test_compose.py
@@ -8,7 +8,7 @@ import pandas as pd
 import pytest
 from sklearn.preprocessing import StandardScaler
 
-from sktime.datasets import load_airline
+from sktime.datasets import load_airline, load_unit_test
 from sktime.datatypes import get_examples
 from sktime.transformations.bootstrap import STLBootstrapTransformer
 from sktime.transformations.compose import (
@@ -173,6 +173,22 @@ def test_featureunion_transform_cols():
     assert deep_equals(Xt.columns, expected_cols), msg
 
 
+def test_featureunion_primitives():
+    """Test that FeatureUnion is correctly applied to primitives.
+
+    Failure case of bug #6077.
+    """
+    X, _ = load_unit_test(split="train", return_X_y=True)
+
+    fu = SummaryTransformer() + SummaryTransformer()
+    Xt = fu.fit_transform(X)
+
+    assert isinstance(Xt, pd.DataFrame)
+    assert len(Xt) == len(X)
+    assert Xt.shape[1] == 2 * 9  # 9-feature summary statistics
+    assert Xt.columns[0] == "SummaryTransformer_1__mean"  # unique naming
+
+
 def test_sklearn_after_primitives():
     """Test that sklearn transformer after primitives is correctly applied."""
     t = SummaryTransformer() * StandardScaler()