Repository: sktime/sktime

Issue:
-inf AIC/BIC in AutoETS
**Is your feature request related to a problem? Please describe.**
Some ETS models from the [statsmodels.tsa.exponential_smoothing.ets.ETSModel](https://www.statsmodels.org/stable/generated/statsmodels.tsa.exponential_smoothing.ets.ETSModel.html) can yield an infinite likelihood. As a result, information criteria like AIC, AICc and BIC will be negative infinity. The AutoETS implementation is picking the model that minimises the chosen information criterion, therefore, in the above case it would choose the infinite likelihood model. For the time series I was playing with this results in many obscure forecasts with a mean MAPE (across splits) of 168%.

**Describe the solution you'd like**
Simply ignoring models with -inf Information Criteria is an effective solution to the problem.
For my time-series, applying this fix causes a reduction in mean MAPE (across splits) from 168% to 13%

**pre vs post -inf IC fix**
![image](https://user-images.githubusercontent.com/64217214/116484582-4661e380-a881-11eb-80e2-e9505772682c.png)  ![image](https://user-images.githubusercontent.com/64217214/116484595-4bbf2e00-a881-11eb-9959-2dd9f78c722a.png)






Discussion:

Resolving patch:
diff --git a/sktime/forecasting/ets.py b/sktime/forecasting/ets.py
--- a/sktime/forecasting/ets.py
+++ b/sktime/forecasting/ets.py
@@ -135,6 +135,10 @@ class AutoETS(_StatsModelsAdapter):
     additive_only : bool, optional
         If True, will only consider additive models.
         Default is False.
+    ignore_inf_ic: bool, optional
+        If True models with negative infinity Information Criterion
+        (aic, bic, aicc) will be ignored.
+        Default is True
     n_jobs : int or None, optional (default=None)
         The number of jobs to run in parallel for automatic model fitting.
         ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context.
@@ -183,6 +187,7 @@ def __init__(
         allow_multiplicative_trend=False,
         restrict=True,
         additive_only=False,
+        ignore_inf_ic=True,
         n_jobs=None,
         **kwargs
     ):
@@ -214,6 +219,7 @@ def __init__(
         self.allow_multiplicative_trend = allow_multiplicative_trend
         self.restrict = restrict
         self.additive_only = additive_only
+        self.ignore_inf_ic = ignore_inf_ic
         self.n_jobs = n_jobs
 
         super(AutoETS, self).__init__()
@@ -299,14 +305,27 @@ def _fit(error, trend, seasonal, damped):
                 )
             )
 
+            # Store IC values for each model in a list
+            # Ignore infinite likelihood models if ignore_inf_ic is True
+            _ic_list = []
+            for result in _fitted_results:
+                ic = getattr(result[1], self.information_criterion)
+                if self.ignore_inf_ic and np.isinf(ic):
+                    _ic_list.append(np.nan)
+                else:
+                    _ic_list.append(ic)
+
             # Select best model based on information criterion
-            # Get index of best model
-            _index = np.argmin(
-                [
-                    getattr(result[1], self.information_criterion)
-                    for result in _fitted_results
-                ]
-            )
+            if np.all(np.isnan(_ic_list)) or len(_ic_list) == 0:
+                # if all models have infinite IC raise an error
+                raise ValueError(
+                    "None of the fitted models have finite %s"
+                    % self.information_criterion
+                )
+            else:
+                # Get index of best model
+                _index = np.nanargmin(_ic_list)
+
             # Update best model
             self._forecaster = _fitted_results[_index][0]
             self._fitted_forecaster = _fitted_results[_index][1]


Test patch:
diff --git a/sktime/forecasting/tests/test_ets.py b/sktime/forecasting/tests/test_ets.py
--- a/sktime/forecasting/tests/test_ets.py
+++ b/sktime/forecasting/tests/test_ets.py
@@ -4,11 +4,19 @@
 from numpy.testing import assert_array_equal
 from sktime.forecasting.ets import AutoETS
 from sktime.datasets import load_airline
+import pandas as pd
+import numpy as np
 
 
 # test results against R implementation on airline dataset
 y = load_airline()
 
+# dummy time series that results in infinite ICs
+inf_ic_ts = pd.Series(
+    10 * np.sin(np.array(range(0, 264)) / 10) + 12,
+    pd.date_range("2017-01-01", periods=264, freq="W"),
+)
+
 
 # Default condition
 # fit <- ets(AirPassengers, model = "ZZZ")
@@ -52,3 +60,29 @@ def test_airline_allow_multiplicative_trend():
     ]
 
     assert_array_equal(fit_result_R, fit_result)
+
+
+# Ignore infinite IC models when ignore_inf_ic is True
+def test_inf_ic_true():
+    forecaster = AutoETS(auto=True, sp=52, n_jobs=-1, ignore_inf_ic=True)
+    forecaster.fit(inf_ic_ts)
+    fitted_forecaster = forecaster._fitted_forecaster
+    # check that none of the information criteria are infinite
+    assert (
+        np.isfinite(fitted_forecaster.aic)
+        and np.isfinite(fitted_forecaster.bic)
+        and np.isfinite(fitted_forecaster.aicc)
+    )
+
+
+# Don't ignore infinite IC models when ignore_inf_ic is False
+def test_inf_ic_false():
+    forecaster = AutoETS(auto=True, sp=52, n_jobs=-1, ignore_inf_ic=False)
+    forecaster.fit(inf_ic_ts)
+    fitted_forecaster = forecaster._fitted_forecaster
+    # check that all of the information criteria are infinite
+    assert (
+        np.isinf(fitted_forecaster.aic)
+        and np.isinf(fitted_forecaster.bic)
+        and np.isinf(fitted_forecaster.aicc)
+    )