docstr: Fit to training data.
  
  Parameters
  ----------
  y : pd.Series
      Target time series to which to fit the forecaster.
  fh : int, list or np.array, optional (default=None)
      The forecasters horizon with the steps ahead to to predict.
  X : pd.DataFrame, optional (default=None)
      Exogenous variables are ignored
  
  Returns
  -------
  self : returns an instance of self.
code: def _fit(self, y, X, fh):
      """Fit to training data.
  
      Parameters
      ----------
      y : pd.Series
          Target time series to which to fit the forecaster.
      fh : int, list or np.array, optional (default=None)
          The forecasters horizon with the steps ahead to to predict.
      X : pd.DataFrame, optional (default=None)
          Exogenous variables are ignored
  
      Returns
      -------
      self : returns an instance of self.
      """
      cv = check_cv(self.cv)
  
      scoring = check_scoring(self.scoring, obj=self)
      scoring_name = f"test_{scoring.name}"
  
      # todo 0.26.0: remove this logic and only use backend_params
      backend = self.backend
      backend_params = (
          self.backend_params if self.backend_params else {}
      )
      if backend in ["threading", "multiprocessing", "loky"]:
          n_jobs = self.n_jobs
          pre_dispatch = self.pre_dispatch
          backend_params["n_jobs"] = n_jobs
          backend_params["pre_dispatch"] = pre_dispatch
          if n_jobs is not None or pre_dispatch is not None:
              warn(
                  f"in {self.__class__.__name__}, n_jobs and pre_dispatch "
                  "parameters are deprecated and will be removed in 0.26.0. "
                  "Please use n_jobs and pre_dispatch directly in the backend_params "
                  "argument instead.",
                  obj=self,
                  stacklevel=2,
              )
  
      def _fit_and_score(params, meta):
          # Clone forecaster.
          forecaster = self.forecaster.clone()
  
          # Set parameters.
          forecaster.set_params(**params)
  
          # Evaluate.
          out = evaluate(
              forecaster,
              cv,
              y,
              X,
              strategy=self.strategy,
              scoring=scoring,
              error_score=self.error_score,
          )
  
          # Filter columns.
          out = out.filter(
              items=[scoring_name, "fit_time", "pred_time"], axis=1
          )
  
          # Aggregate results.
          out = out.mean()
          out = out.add_prefix("mean_")
  
          # Add parameters to output table.
          out["params"] = params
  
          return out
  
      def evaluate_candidates(candidate_params):
          candidate_params = list(candidate_params)
  
          if self.verbose > 0:
              n_candidates = len(candidate_params)
              n_splits = cv.get_n_splits(y)
              print(  # noqa
                  "Fitting {} folds for each of {} candidates,"
                  " totalling {} fits".format(
                      n_splits, n_candidates, n_candidates * n_splits
                  )
              )
  
          out = parallelize(
              fun=_fit_and_score,
              iter=candidate_params,
              backend=backend,
              backend_params=backend_params,
          )
  
          if len(out) < 1:
              raise ValueError(
                  "No fits were performed. "
                  "Was the CV iterator empty? "
                  "Were there no candidates?"
              )
  
          return out
  
      # Run grid-search cross-validation.
      results = self._run_search(evaluate_candidates)
  
      results = pd.DataFrame(results)
  
      # Rank results, according to whether greater is better for the given scoring.
      results[f"rank_{scoring_name}"] = results.loc[
          :, f"mean_{scoring_name}"
      ].rank(ascending=scoring.get_tag("lower_is_better"))
  
      self.cv_results_ = results
  
      # Select best parameters.
      self.best_index_ = results.loc[:, f"rank_{scoring_name}"].argmin()
      # Raise error if all fits in evaluate failed because all score values are NaN.
      if self.best_index_ == -1:
          raise NotFittedError(
              f"""All fits of forecaster failed,
                  set error_score='raise' to see the exceptions.
                  Failed forecaster: {self.forecaster}"""
          )
      self.best_score_ = results.loc[
          self.best_index_, f"mean_{scoring_name}"
      ]
      self.best_params_ = results.loc[self.best_index_, "params"]
      self.best_forecaster_ = self.forecaster.clone().set_params(
          **self.best_params_
      )
  
      # Refit model with best parameters.
      if self.refit:
          self.best_forecaster_.fit(y=y, X=X, fh=fh)
  
      # Sort values according to rank
      results = results.sort_values(
          by=f"rank_{scoring_name}",
          ascending=True,
      )
      # Select n best forecaster
      self.n_best_forecasters_ = []
      self.n_best_scores_ = []
      for i in range(self.return_n_best_forecasters):
          params = results["params"].iloc[i]
          rank = results[f"rank_{scoring_name}"].iloc[i]
          rank = str(int(rank))
          forecaster = self.forecaster.clone().set_params(**params)
          # Refit model with best parameters.
          if self.refit:
              forecaster.fit(y=y, X=X, fh=fh)
          self.n_best_forecasters_.append((rank, forecaster))
          # Save score
          score = results[f"mean_{scoring_name}"].iloc[i]
          self.n_best_scores_.append(score)
  
      return self
  
imports: from collections.abc import Sequence
  from typing import Dict, List, Optional, Union
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from sklearn.model_selection import ParameterGrid, ParameterSampler, check_cv
  from sktime.datatypes import mtype_to_scitype
  from sktime.exceptions import NotFittedError
  from sktime.forecasting.base._delegate import _DelegatedForecaster
  from sktime.forecasting.model_evaluation import evaluate
  from sktime.performance_metrics.base import BaseMetric
  from sktime.split.base import BaseSplitter
  from sktime.utils.parallel import parallelize
  from sktime.utils.validation.forecasting import check_scoring
  from sktime.utils.warnings import warn
label_desc: Use image node_id 5 for calling the BaseGridSearch obj's underlying member method code with example usage: obj._fit(y, X, fh) and returns: self, out, out