Repository: sktime/sktime

Issue:
[ENH] pass `statsmodels` `fit_params` to constructor
From discord, indirect request by ckwan48.

The `SARIMAX` model interfacing `statmodels` does not allow to specify the parameters that `statsmodels` would receive in `fit`. These should be specified in the `sktime` constructor.
Good first issue as a recipe is available, here:
(similar to #2344)

---

Recipe for interfacing models with `fit_params` or any other `fit` args, in sktime:

* pass the parameter(s) to the constructor (the `__init__` method), using explicit parameter names and default, not `**kwargs`
* write it to `self` in the constructor
* in `_fit`, read it from `self` and pass it to the wrapped model's `fit` method
* ensure docstring is complete and defaults documented (optimally same as in wrapped estimator)

This allows to expose all parameter choices via the scikit-learn compatible interface (which relies on the constructor to expose all parameter choices).

For an example of this, you can look at `smoothing_level` in `ExponentialSmoothing`.


Discussion:
I would Like to work on this issue , will you please assign this issue to me ?

Sure, it's all yours!
@AishwaryaSatpute1, are you still working on this?
If so, as @yarnabrina noted here https://github.com/sktime/sktime/pull/4439#issue-1656568085, it might make sense to add `simple_differencing` in the same PR.
Noting the list of available `fit` parameters for easy reference in future.

https://www.statsmodels.org/dev/generated/statsmodels.tsa.statespace.sarimax.SARIMAX.fit.html#statsmodels.tsa.statespace.sarimax.SARIMAX.fit-parameters

Resolving patch:
diff --git a/sktime/forecasting/sarimax.py b/sktime/forecasting/sarimax.py
--- a/sktime/forecasting/sarimax.py
+++ b/sktime/forecasting/sarimax.py
@@ -88,10 +88,100 @@ class SARIMAX(_StatsModelsAdapter):
     disp : bool, optional, default=False
         Set to True to print convergence messages.
     random_state : int, RandomState instance or None, optional, default=None
-        default=None – If int, random_state is the seed used by the random
+        default=None - If int, random_state is the seed used by the random
         number generator; If RandomState instance, random_state is the random
         number generator; If None, the random number generator is the
         RandomState instance used by np.random.
+    start_params : array_like, optional
+        Initial guess of the solution for the loglikelihood maximization. If None, the
+        default is given by SARIMAX.start_params.
+    transformed : bool, optional
+        Whether or not `start_params` is already transformed. Default is True.
+    includes_fixed : bool, optional
+        If parameters were previously fixed with the `fix_params` method, this argument
+        describes whether or not `start_params` also includes the fixed parameters, in
+        addition to the free parameters. Default is False.
+    cov_type : str, optional
+        The `cov_type` keyword governs the method for calculating the covariance matrix
+        of parameter estimates. Can be one of:
+
+        - 'opg' for the outer product of gradient estimator
+        - 'oim' for the observed information matrix estimator, calculated
+            using the method of Harvey (1989)
+        - 'approx' for the observed information matrix estimator, calculated using a
+            numerical approximation of the Hessian matrix.
+        - 'robust' for an approximate (quasi-maximum likelihood) covariance matrix that
+            may be valid even in the presence of some misspecifications. Intermediate
+            calculations use the 'oim' method.
+        - 'robust_approx' is the same as 'robust' except that the intermediate
+            calculations use the 'approx' method.
+        - 'none' for no covariance matrix calculation.
+
+        Default is 'opg' unless memory conservation is used to avoid
+        computing the loglikelihood values for each observation, in which
+        case the default is 'approx'.
+    cov_kwds : dict or None, optional
+        A dictionary of arguments affecting covariance matrix computation.
+
+        **opg, oim, approx, robust, robust_approx**
+
+        - 'approx_complex_step' : bool, optional - If True, numerical
+            approximations are computed using complex-step methods. If False, numerical
+            approximations are computed using finite difference methods. Default is
+            True.
+        - 'approx_centered' : bool, optional - If True, numerical
+            approximations computed using finite difference methods use a centered
+            approximation. Default is False.
+    method : str, optional
+        The `method` determines which solver from `scipy.optimize` is used, and it can
+        be chosen from among the following strings:
+
+        - 'newton' for Newton-Raphson
+        - 'nm' for Nelder-Mead
+        - 'bfgs' for Broyden-Fletcher-Goldfarb-Shanno (BFGS)
+        - 'lbfgs' for limited-memory BFGS with optional box constraints
+        - 'powell' for modified Powell's method
+        - 'cg' for conjugate gradient
+        - 'ncg' for Newton-conjugate gradient
+        - 'basinhopping' for global basin-hopping solver
+
+        The explicit arguments in `fit` are passed to the solver, with the exception of
+        the basin-hopping solver. Each solver has several optional arguments that are
+        not the same across solvers. See the notes section below (or scipy.optimize) for
+        the available arguments and for the list of explicit arguments that the
+        basin-hopping solver supports.
+    maxiter : int, optional
+        The maximum number of iterations to perform.
+    full_output : bool, optional
+        Set to True to have all available output in the Results object's mle_retvals
+        attribute. The output is dependent on the solver. See LikelihoodModelResults
+        notes section for more information.
+    callback : callable callback(xk), optional
+        Called after each iteration, as callback(xk), where xk is the current parameter
+        vector.
+    return_params : bool, optional
+        Whether or not to return only the array of maximizing parameters. Default is
+        False.
+    optim_score : {'harvey', 'approx'} or None, optional
+        The method by which the score vector is calculated. 'harvey' uses the method
+        from Harvey (1989), 'approx' uses either finite difference or complex step
+        differentiation depending upon the value of `optim_complex_step`, and None uses
+        the built-in gradient approximation of the optimizer. Default is None. This
+        keyword is only relevant if the optimization method uses the score.
+    optim_complex_step : bool, optional
+        Whether or not to use complex step differentiation when approximating the score;
+        if False, finite difference approximation is used. Default is True. This keyword
+        is only relevant if `optim_score` is set to 'harvey' or 'approx'.
+    optim_hessian : {'opg','oim','approx'}, optional
+        The method by which the Hessian is numerically approximated. 'opg' uses outer
+        product of gradients, 'oim' uses the information matrix formula from Harvey
+        (1989), and 'approx' uses numerical approximation. This keyword is only relevant
+        if the optimization method uses the Hessian matrix.
+    low_memory : bool, optional
+        If set to True, techniques are applied to substantially reduce memory usage. If
+        used, some features of the results object will not be available (including
+        smoothed results and in-sample prediction), although out-of-sample forecasting
+        is possible. Default is False.
 
     See Also
     --------
@@ -144,6 +234,20 @@ def __init__(
         validate_specification=True,
         disp=False,
         random_state=None,
+        start_params=None,
+        transformed=True,
+        includes_fixed=False,
+        cov_type=None,
+        cov_kwds=None,
+        method="lbfgs",
+        maxiter=50,
+        full_output=1,
+        callback=None,
+        return_params=False,
+        optim_score=None,
+        optim_complex_step=None,
+        optim_hessian=None,
+        low_memory=False,
     ):
         self.order = order
         self.seasonal_order = seasonal_order
@@ -165,6 +269,20 @@ def __init__(
 
         # Fit params
         self.disp = disp
+        self.start_params = start_params
+        self.transformed = transformed
+        self.includes_fixed = includes_fixed
+        self.cov_type = cov_type
+        self.cov_kwds = cov_kwds
+        self.method = method
+        self.maxiter = maxiter
+        self.full_output = full_output
+        self.callback = callback
+        self.return_params = return_params
+        self.optim_score = optim_score
+        self.optim_complex_step = optim_complex_step
+        self.optim_hessian = optim_hessian
+        self.low_memory = low_memory
 
         super().__init__(random_state=random_state)
 
@@ -192,7 +310,23 @@ def _fit_forecaster(self, y, X=None):
             missing=self.missing,
             validate_specification=self.validate_specification,
         )
-        self._fitted_forecaster = self._forecaster.fit(disp=self.disp)
+        self._fitted_forecaster = self._forecaster.fit(
+            disp=self.disp,
+            start_params=self.start_params,
+            transformed=self.transformed,
+            includes_fixed=self.includes_fixed,
+            cov_type=self.cov_type,
+            cov_kwds=self.cov_kwds,
+            method=self.method,
+            maxiter=self.maxiter,
+            full_output=self.full_output,
+            callback=self.callback,
+            return_params=self.return_params,
+            optim_score=self.optim_score,
+            optim_complex_step=self.optim_complex_step,
+            optim_hessian=self.optim_hessian,
+            low_memory=self.low_memory,
+        )
 
     def summary(self):
         """Get a summary of the fitted forecaster.
@@ -274,4 +408,5 @@ def get_test_params(cls, parameter_set="default"):
                 "hamilton_representation": True,
                 "simple_differencing": True,
             },
+            {"cov_type": "robust", "method": "bfgs", "maxiter": 5},
         ]


Test patch: