class_docstr: Abstract class for local forecasting models that are trained separately for each time series.
  
  Prediction is parallelized across CPU cores using joblib.Parallel.
  
  Attributes
  ----------
  allowed_local_model_args : List[str]
      Argument that can be passed to the underlying local model.
  default_n_jobs : Union[int, float]
      Default number of CPU cores used to train models. If float, this fraction of CPU cores will be used.
  default_max_ts_length : Optional[int]
      If not None, only the last ``max_ts_length`` time steps of each time series will be used to train the model.
      This significantly speeds up fitting and usually leads to no change in accuracy.
  init_time_in_seconds : int
      Time that it takes to initialize the model in seconds (e.g., because of JIT compilation by Numba).
      If time_limit is below this number, model won't be trained.
code: def _predict(
      self, data: TimeSeriesDataFrame, **kwargs
  ) -> TimeSeriesDataFrame:
      if self.max_ts_length is not None:
          logger.debug(
              f"Shortening all time series to at most {self.max_ts_length}"
          )
          data = data.groupby(level=ITEMID, sort=False).tail(
              self.max_ts_length
          )
  
      df = pd.DataFrame(data).reset_index(level=ITEMID)
      all_series = (
          ts
          for _, ts in df.groupby(
              by=ITEMID, as_index=False, sort=False
          )[self.target]
      )
  
      # timeout ensures that no individual job takes longer than time_limit
      # TODO: a job started late may still exceed time_limit - how to prevent that?
      timeout = None if self.n_jobs == 1 else self.time_limit
      # end_time ensures that no new jobs are started after time_limit is exceeded
      end_time = (
          None
          if self.time_limit is None
          else time.time() + self.time_limit
      )
      executor = Parallel(self.n_jobs, timeout=timeout)
  
      try:
          with warning_filter():
              predictions_with_flags = executor(
                  delayed(self._predict_wrapper)(ts, end_time=end_time)
                  for ts in all_series
              )
      except TimeoutError:
          raise TimeLimitExceeded
  
      number_failed_models = sum(
          failed_flag for _, failed_flag in predictions_with_flags
      )
      if number_failed_models > 0:
          fraction_failed_models = number_failed_models / len(
              predictions_with_flags
          )
          logger.warning(
              f"\tWarning: {self.name} failed for {number_failed_models} time series "
              f"({fraction_failed_models:.1%}). Fallback model SeasonalNaive was used for these time series."
          )
      predictions_df = pd.concat(
          [pred for pred, _ in predictions_with_flags]
      )
      predictions_df.index = get_forecast_horizon_index_ts_dataframe(
          data, self.prediction_length
      )
      return TimeSeriesDataFrame(predictions_df)
  
imports: import logging
  import time
  from multiprocessing import TimeoutError, cpu_count
  from typing import Any, Dict, List, Optional, Tuple, Union
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from scipy.stats import norm
  from autogluon.common.utils.log_utils import set_logger_verbosity
  from autogluon.core.utils.exceptions import TimeLimitExceeded
  from autogluon.timeseries.dataset.ts_dataframe import ITEMID, TimeSeriesDataFrame
  from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
  from autogluon.timeseries.utils.datetime import get_seasonality
  from autogluon.timeseries.utils.forecast import get_forecast_horizon_index_ts_dataframe
  from autogluon.timeseries.utils.warning_filters import warning_filter
label_desc: Use image node_id 4 for calling the AbstractLocalModel obj's underlying member method code with example usage: obj._predict(data) and returns: TimeSeriesDataFrame