class_docstr: This class turns any regressor compatible with the scikit-learn API into a
  autoregressive multivariate direct multi-step forecaster. A separate model 
  is created for each forecast time step. See documentation for more details.
  
  Parameters
  ----------
  regressor : regressor or pipeline compatible with the scikit-learn API
      An instance of a regressor or pipeline compatible with the scikit-learn API.
  level : str
      Name of the time series to be predicted.
  steps : int
      Maximum number of future steps the forecaster will predict when using
      method `predict()`. Since a different model is created for each step,
      this value must be defined before training.
  lags : int, list, numpy ndarray, range, dict
      Lags used as predictors. Index starts at 1, so lag 1 is equal to t-1.
  
      - `int`: include lags from 1 to `lags` (included).
      - `list`, `1d numpy ndarray` or `range`: include only lags present in 
      `lags`, all elements must be int.
      - `dict`: create different lags for each series. {'series_column_name': lags}.
  transformer_series : transformer (preprocessor), dict, default `sklearn.preprocessing.StandardScaler`
      An instance of a transformer (preprocessor) compatible with the scikit-learn
      preprocessing API with methods: fit, transform, fit_transform and 
      inverse_transform. Transformation is applied to each `series` before training 
      the forecaster. ColumnTransformers are not allowed since they do not have 
      inverse_transform method.
  
      - If single transformer: it is cloned and applied to all series. 
      - If `dict` of transformers: a different transformer can be used for each series.
  transformer_exog : transformer, default `None`
      An instance of a transformer (preprocessor) compatible with the scikit-learn
      preprocessing API. The transformation is applied to `exog` before training the
      forecaster. `inverse_transform` is not available when using ColumnTransformers.
  weight_func : Callable, default `None`
      Function that defines the individual weights for each sample based on the
      index. For example, a function that assigns a lower weight to certain dates.
      Ignored if `regressor` does not have the argument `sample_weight` in its `fit`
      method. The resulting `sample_weight` cannot have negative values.
  fit_kwargs : dict, default `None`
      Additional arguments to be passed to the `fit` method of the regressor.
  n_jobs : int, 'auto', default `'auto'`
      The number of jobs to run in parallel. If `-1`, then the number of jobs is 
      set to the number of cores. If 'auto', `n_jobs` is set using the function
      skforecast.utils.select_n_jobs_fit_forecaster.
      **New in version 0.9.0**
  forecaster_id : str, int, default `None`
      Name used as an identifier of the forecaster.
  
  Attributes
  ----------
  regressor : regressor or pipeline compatible with the scikit-learn API
      An instance of a regressor or pipeline compatible with the scikit-learn API.
      An instance of this regressor is trained for each step. All of them 
      are stored in `self.regressors_`.
  regressors_ : dict
      Dictionary with regressors trained for each step. They are initialized 
      as a copy of `regressor`.
  steps : int
      Number of future steps the forecaster will predict when using method
      `predict()`. Since a different model is created for each step, this value
      should be defined before training.
  lags : numpy ndarray, dict
      Lags used as predictors.
  lags_ : dict
      Dictionary containing the lags of each series. Created from `lags` and 
      used internally.
  transformer_series : transformer (preprocessor), dict, default `None`
      An instance of a transformer (preprocessor) compatible with the scikit-learn
      preprocessing API with methods: fit, transform, fit_transform and 
      inverse_transform. Transformation is applied to each `series` before training 
      the forecaster. ColumnTransformers are not allowed since they do not have 
      inverse_transform method.
  
      - If single transformer: it is cloned and applied to all series. 
      - If `dict` of transformers: a different transformer can be used for each series.
  transformer_series_ : dict
      Dictionary with the transformer for each series. It is created cloning the 
      objects in `transformer_series` and is used internally to avoid overwriting.
  transformer_exog : transformer
      An instance of a transformer (preprocessor) compatible with the scikit-learn
      preprocessing API. The transformation is applied to `exog` before training the
      forecaster. `inverse_transform` is not available when using ColumnTransformers.
  weight_func : Callable
      Function that defines the individual weights for each sample based on the
      index. For example, a function that assigns a lower weight to certain dates.
      Ignored if `regressor` does not have the argument `sample_weight` in its
      `fit` method. The resulting `sample_weight` cannot have negative values.
  source_code_weight_func : str
      Source code of the custom function used to create weights.
  max_lag : int
      Maximum value of lag included in `lags`.
  window_size : int
      Size of the window needed to create the predictors. It is equal to
      `max_lag`.
  last_window : pandas Series
      Last window seen by the forecaster during training. It stores the values 
      needed to predict the next `step` immediately after the training data.   
  index_type : type
      Type of index of the input used in training.
  index_freq : str
      Frequency of Index of the input used in training.
  training_range: pandas Index
      First and last values of index of the data used during training.
  included_exog : bool
      If the forecaster has been trained using exogenous variable/s.
  exog_type : type
      Type of exogenous variable/s used in training.
  exog_dtypes : dict
      Type of each exogenous variable/s used in training. If `transformer_exog` 
      is used, the dtypes are calculated after the transformation.
  exog_col_names : list
      Names of columns of `exog` if `exog` used in training was a pandas
      DataFrame.
  series_col_names : list
      Names of the series used during training.
  X_train_col_names : list
      Names of columns of the matrix created internally for training.
  fit_kwargs : dict
      Additional arguments to be passed to the `fit` method of the regressor.
  in_sample_residuals : dict
      Residuals of the models when predicting training data. Only stored up to
      1000 values per model in the form `{step: residuals}`. If `transformer_series` 
      is not `None`, residuals are stored in the transformed scale.
  out_sample_residuals : dict
      Residuals of the models when predicting non training data. Only stored
      up to 1000 values per model in the form `{step: residuals}`. If `transformer_series` 
      is not `None`, residuals are assumed to be in the transformed scale. Use 
      `set_out_sample_residuals()` method to set values.
  fitted : bool
      Tag to identify if the regressor has been fitted (trained).
  creation_date : str
      Date of creation.
  fit_date : str
      Date of last fit.
  skforecast_version : str
      Version of skforecast library used to create the forecaster.
  python_version : str
      Version of python used to create the forecaster.
  n_jobs : int, 'auto', default `'auto'`
      The number of jobs to run in parallel. If `-1`, then the number of jobs is 
      set to the number of cores. If 'auto', `n_jobs` is set using the fuction
      skforecast.utils.select_n_jobs_fit_forecaster.
      **New in version 0.9.0**
  forecaster_id : str, int
      Name used as an identifier of the forecaster.
  
  Notes
  -----
  A separate model is created for each forecasting time step. It is important to
  note that all models share the same parameter and hyperparameter configuration.
class_docstr_tok: ["This","class","turns","any","regressor","compatible","with","the","scikit-learn","API","into","a","autoregressive","multivariate","direct","multi-step","forecaster",".","A","separate","model","is","created","for","each","forecast","time","step",".","See","documentation","for","more","details",".","Parameters","--","--","--","--","--","regressor",":","regressor","or","pipeline","compatible","with","the","scikit-learn","API","An","instance","of","a","regressor","or","pipeline","compatible","with","the","scikit-learn","API",".","level",":","str","Name","of","the","time","series","to","be","predicted",".","steps",":","int","Maximum","number","of","future","steps","the","forecaster","will","predict","when","using","method","`","predict","(",")","`",".","Since","a","different","model","is","created","for","each","step",",","this","value","must","be","defined","before","training",".","lags",":","int",",","list",",","numpy","ndarray",",","range",",","dict","Lags","used","as","predictors",".","Index","starts","at","1",",","so","lag","1","is","equal","to","t-1",".","-","`","int","`",":","include","lags","from","1","to","`","lags","`","(","included",")",".","-","`","list","`",",","`","1d","numpy","ndarray","`","or","`","range","`",":","include","only","lags","present","in","`","lags","`",",","all","elements","must","be","int",".","-","`","dict","`",":","create","different","lags","for","each","series",".","{","'series_column_name","'",":","lags","}",".","transformer_series",":","transformer","(","preprocessor",")",",","dict",",","default","`","sklearn.preprocessing.StandardScaler","`","An","instance","of","a","transformer","(","preprocessor",")","compatible","with","the","scikit-learn","preprocessing","API","with","methods",":","fit",",","transform",",","fit_transform","and","inverse_transform",".","Transformation","is","applied","to","each","`","series","`","before","training","the","forecaster",".","ColumnTransformers","are","not","allowed","since","they","do","not","have","inverse_transform","method",".","-","If","single","transformer",":","it","is","cloned","and","applied","to","all","series",".","-","If","`","dict","`","of","transformers",":","a","different","transformer","can","be","used","for","each","series",".","transformer_exog",":","transformer",",","default","`","None","`","An","instance","of","a","transformer","(","preprocessor",")","compatible","with","the","scikit-learn","preprocessing","API",".","The","transformation","is","applied","to","`","exog","`","before","training","the","forecaster",".","`","inverse_transform","`","is","not","available","when","using","ColumnTransformers",".","weight_func",":","Callable",",","default","`","None","`","Function","that","defines","the","individual","weights","for","each","sample","based","on","the","index",".","For","example",",","a","function","that","assigns","a","lower","weight","to","certain","dates",".","Ignored","if","`","regressor","`","does","not","have","the","argument","`","sample_weight","`","in","its","`","fit","`","method",".","The","resulting","`","sample_weight","`","can","not","have","negative","values",".","fit_kwargs",":","dict",",","default","`","None","`","Additional","arguments","to","be","passed","to","the","`","fit","`","method","of","the","regressor",".","n_jobs",":","int",",","'auto","'",",","default","`","'auto","'","`","The","number","of","jobs","to","run","in","parallel",".","If","`","-1","`",",","then","the","number","of","jobs","is","set","to","the","number","of","cores",".","If","'auto","'",",","`","n_jobs","`","is","set","using","the","function","skforecast.utils.select_n_jobs_fit_forecaster",".","*","*","New","in","version","0.9.0","*","*","forecaster_id",":","str",",","int",",","default","`","None","`","Name","used","as","an","identifier","of","the","forecaster",".","Attributes","--","--","--","--","--","regressor",":","regressor","or","pipeline","compatible","with","the","scikit-learn","API","An","instance","of","a","regressor","or","pipeline","compatible","with","the","scikit-learn","API",".","An","instance","of","this","regressor","is","trained","for","each","step",".","All","of","them","are","stored","in","`","self.regressors_","`",".","regressors_",":","dict","Dictionary","with","regressors","trained","for","each","step",".","They","are","initialized","as","a","copy","of","`","regressor","`",".","steps",":","int","Number","of","future","steps","the","forecaster","will","predict","when","using","method","`","predict","(",")","`",".","Since","a","different","model","is","created","for","each","step",",","this","value","should","be","defined","before","training",".","lags",":","numpy","ndarray",",","dict","Lags","used","as","predictors",".","lags_",":","dict","Dictionary","containing","the","lags","of","each","series",".","Created","from","`","lags","`","and","used","internally",".","transformer_series",":","transformer","(","preprocessor",")",",","dict",",","default","`","None","`","An","instance","of","a","transformer","(","preprocessor",")","compatible","with","the","scikit-learn","preprocessing","API","with","methods",":","fit",",","transform",",","fit_transform","and","inverse_transform",".","Transformation","is","applied","to","each","`","series","`","before","training","the","forecaster",".","ColumnTransformers","are","not","allowed","since","they","do","not","have","inverse_transform","method",".","-","If","single","transformer",":","it","is","cloned","and","applied","to","all","series",".","-","If","`","dict","`","of","transformers",":","a","different","transformer","can","be","used","for","each","series",".","transformer_series_",":","dict","Dictionary","with","the","transformer","for","each","series",".","It","is","created","cloning","the","objects","in","`","transformer_series","`","and","is","used","internally","to","avoid","overwriting",".","transformer_exog",":","transformer","An","instance","of","a","transformer","(","preprocessor",")","compatible","with","the","scikit-learn","preprocessing","API",".","The","transformation","is","applied","to","`","exog","`","before","training","the","forecaster",".","`","inverse_transform","`","is","not","available","when","using","ColumnTransformers",".","weight_func",":","Callable","Function","that","defines","the","individual","weights","for","each","sample","based","on","the","index",".","For","example",",","a","function","that","assigns","a","lower","weight","to","certain","dates",".","Ignored","if","`","regressor","`","does","not","have","the","argument","`","sample_weight","`","in","its","`","fit","`","method",".","The","resulting","`","sample_weight","`","can","not","have","negative","values",".","source_code_weight_func",":","str","Source","code","of","the","custom","function","used","to","create","weights",".","max_lag",":","int","Maximum","value","of","lag","included","in","`","lags","`",".","window_size",":","int","Size","of","the","window","needed","to","create","the","predictors",".","It","is","equal","to","`","max_lag","`",".","last_window",":","pandas","Series","Last","window","seen","by","the","forecaster","during","training",".","It","stores","the","values","needed","to","predict","the","next","`","step","`","immediately","after","the","training","data",".","index_type",":","type","Type","of","index","of","the","input","used","in","training",".","index_freq",":","str","Frequency","of","Index","of","the","input","used","in","training",".","training_range",":","pandas","Index","First","and","last","values","of","index","of","the","data","used","during","training",".","included_exog",":","bool","If","the","forecaster","has","been","trained","using","exogenous","variable\/s",".","exog_type",":","type","Type","of","exogenous","variable\/s","used","in","training",".","exog_dtypes",":","dict","Type","of","each","exogenous","variable\/s","used","in","training",".","If","`","transformer_exog","`","is","used",",","the","dtypes","are","calculated","after","the","transformation",".","exog_col_names",":","list","Names","of","columns","of","`","exog","`","if","`","exog","`","used","in","training","was","a","pandas","DataFrame",".","series_col_names",":","list","Names","of","the","series","used","during","training",".","X_train_col_names",":","list","Names","of","columns","of","the","matrix","created","internally","for","training",".","fit_kwargs",":","dict","Additional","arguments","to","be","passed","to","the","`","fit","`","method","of","the","regressor",".","in_sample_residuals",":","dict","Residuals","of","the","models","when","predicting","training","data",".","Only","stored","up","to","1000","values","per","model","in","the","form","`","{","step",":","residuals","}","`",".","If","`","transformer_series","`","is","not","`","None","`",",","residuals","are","stored","in","the","transformed","scale",".","out_sample_residuals",":","dict","Residuals","of","the","models","when","predicting","non","training","data",".","Only","stored","up","to","1000","values","per","model","in","the","form","`","{","step",":","residuals","}","`",".","If","`","transformer_series","`","is","not","`","None","`",",","residuals","are","assumed","to","be","in","the","transformed","scale",".","Use","`","set_out_sample_residuals","(",")","`","method","to","set","values",".","fitted",":","bool","Tag","to","identify","if","the","regressor","has","been","fitted","(","trained",")",".","creation_date",":","str","Date","of","creation",".","fit_date",":","str","Date","of","last","fit",".","skforecast_version",":","str","Version","of","skforecast","library","used","to","create","the","forecaster",".","python_version",":","str","Version","of","python","used","to","create","the","forecaster",".","n_jobs",":","int",",","'auto","'",",","default","`","'auto","'","`","The","number","of","jobs","to","run","in","parallel",".","If","`","-1","`",",","then","the","number","of","jobs","is","set","to","the","number","of","cores",".","If","'auto","'",",","`","n_jobs","`","is","set","using","the","fuction","skforecast.utils.select_n_jobs_fit_forecaster",".","*","*","New","in","version","0.9.0","*","*","forecaster_id",":","str",",","int","Name","used","as","an","identifier","of","the","forecaster",".","Notes","--","--","-","A","separate","model","is","created","for","each","forecasting","time","step",".","It","is","important","to","note","that","all","models","share","the","same","parameter","and","hyperparameter","configuration","."]
docstr: Generate multiple forecasting predictions using a bootstrapping process. 
  By sampling from a collection of past observed errors (the residuals),
  each iteration of bootstrapping generates a different set of predictions. 
  See the Notes section for more information. 
  
  Parameters
  ----------
  steps : int, list, None, default `None`
      Predict n steps. The value of `steps` must be less than or equal to the 
      value of steps defined when initializing the forecaster. Starts at 1.
  
      - If `int`: Only steps within the range of 1 to int are predicted.
      - If `list`: List of ints. Only the steps contained in the list 
      are predicted.
      - If `None`: As many steps are predicted as were defined at 
      initialization.
  last_window : pandas DataFrame, default `None`
      Series values used to create the predictors (lags) needed in the 
      first iteration of the prediction (t + 1).
      If `last_window = None`, the values stored in` self.last_window` are
      used to calculate the initial predictors, and the predictions start
      right after training data.
  exog : pandas Series, pandas DataFrame, default `None`
      Exogenous variable/s included as predictor/s.     
  n_boot : int, default `500`
      Number of bootstrapping iterations used to estimate predictions.
  random_state : int, default `123`
      Sets a seed to the random generator, so that boot predictions are always 
      deterministic.               
  in_sample_residuals : bool, default `True`
      If `True`, residuals from the training data are used as proxy of
      prediction error to create predictions. If `False`, out of sample 
      residuals are used. In the latter case, the user should have
      calculated and stored the residuals within the forecaster (see
      `set_out_sample_residuals()`).
  levels : Ignored
      Not used, present here for API consistency by convention.
  
  Returns
  -------
  boot_predictions : pandas DataFrame
      Predictions generated by bootstrapping.
      Shape: (steps, n_boot)
  
  Notes
  -----
  More information about prediction intervals in forecasting:
  https://otexts.com/fpp3/prediction-intervals.html#prediction-intervals-from-bootstrapped-residuals
  Forecasting: Principles and Practice (3nd ed) Rob J Hyndman and George Athanasopoulos.
code: def predict_bootstrapping(
      self,
      steps: Optional[Union[int, list]] = None,
      last_window: Optional[pd.DataFrame] = None,
      exog: Optional[Union[pd.Series, pd.DataFrame]] = None,
      n_boot: int = 500,
      random_state: int = 123,
      in_sample_residuals: bool = True,
      levels: Any = None,
  ) -> pd.DataFrame:
      """
      Generate multiple forecasting predictions using a bootstrapping process.
      By sampling from a collection of past observed errors (the residuals),
      each iteration of bootstrapping generates a different set of predictions.
      See the Notes section for more information.
  
      Parameters
      ----------
      steps : int, list, None, default `None`
          Predict n steps. The value of `steps` must be less than or equal to the
          value of steps defined when initializing the forecaster. Starts at 1.
  
          - If `int`: Only steps within the range of 1 to int are predicted.
          - If `list`: List of ints. Only the steps contained in the list
          are predicted.
          - If `None`: As many steps are predicted as were defined at
          initialization.
      last_window : pandas DataFrame, default `None`
          Series values used to create the predictors (lags) needed in the
          first iteration of the prediction (t + 1).
          If `last_window = None`, the values stored in` self.last_window` are
          used to calculate the initial predictors, and the predictions start
          right after training data.
      exog : pandas Series, pandas DataFrame, default `None`
          Exogenous variable/s included as predictor/s.
      n_boot : int, default `500`
          Number of bootstrapping iterations used to estimate predictions.
      random_state : int, default `123`
          Sets a seed to the random generator, so that boot predictions are always
          deterministic.
      in_sample_residuals : bool, default `True`
          If `True`, residuals from the training data are used as proxy of
          prediction error to create predictions. If `False`, out of sample
          residuals are used. In the latter case, the user should have
          calculated and stored the residuals within the forecaster (see
          `set_out_sample_residuals()`).
      levels : Ignored
          Not used, present here for API consistency by convention.
  
      Returns
      -------
      boot_predictions : pandas DataFrame
          Predictions generated by bootstrapping.
          Shape: (steps, n_boot)
  
      Notes
      -----
      More information about prediction intervals in forecasting:
      https://otexts.com/fpp3/prediction-intervals.html#prediction-intervals-from-bootstrapped-residuals
      Forecasting: Principles and Practice (3nd ed) Rob J Hyndman and George Athanasopoulos.
  
      """
  
      if self.fitted:
          if isinstance(steps, int):
              steps = list(np.arange(steps) + 1)
          elif steps is None:
              steps = list(np.arange(self.steps) + 1)
          elif isinstance(steps, list):
              steps = list(np.array(steps))
  
          if in_sample_residuals:
              if not set(steps).issubset(
                  set(self.in_sample_residuals.keys())
              ):
                  raise ValueError(
                      (
                          f"Not `forecaster.in_sample_residuals` for steps: "
                          f"{set(steps) - set(self.in_sample_residuals.keys())}."
                      )
                  )
              residuals = self.in_sample_residuals
          else:
              if self.out_sample_residuals is None:
                  raise ValueError(
                      (
                          "`forecaster.out_sample_residuals` is `None`. Use "
                          "`in_sample_residuals=True` or method `set_out_sample_residuals()` "
                          "before `predict_interval()`, `predict_bootstrapping()`, "
                          "`predict_quantiles()` or `predict_dist()`."
                      )
                  )
              else:
                  if not set(steps).issubset(
                      set(self.out_sample_residuals.keys())
                  ):
                      raise ValueError(
                          (
                              f"Not `forecaster.out_sample_residuals` for steps: "
                              f"{set(steps) - set(self.out_sample_residuals.keys())}. "
                              f"Use method `set_out_sample_residuals()`."
                          )
                      )
              residuals = self.out_sample_residuals
  
          check_residuals = (
              "forecaster.in_sample_residuals"
              if in_sample_residuals
              else "forecaster.out_sample_residuals"
          )
          for step in steps:
              if residuals[step] is None:
                  raise ValueError(
                      (
                          f"forecaster residuals for step {step} are `None`. "
                          f"Check {check_residuals}."
                      )
                  )
              elif any(
                  element is None for element in residuals[step]
              ) or np.any(np.isnan(residuals[step])):
                  raise ValueError(
                      (
                          f"forecaster residuals for step {step} contains `None` "
                          f"or `NaNs` values. Check {check_residuals}."
                      )
                  )
  
      predictions = self.predict(
          steps=steps, last_window=last_window, exog=exog
      )
  
      # Predictions must be in the transformed scale before adding residuals
      predictions = transform_dataframe(
          df=predictions,
          transformer=self.transformer_series_[self.level],
          fit=False,
          inverse_transform=False,
      )
      boot_predictions = pd.concat([predictions] * n_boot, axis=1)
      boot_predictions.columns = [
          f"pred_boot_{i}" for i in range(n_boot)
      ]
  
      for i, step in enumerate(steps):
          rng = np.random.default_rng(seed=random_state)
          sample_residuals = rng.choice(
              a=residuals[step], size=n_boot, replace=True
          )
          boot_predictions.iloc[i, :] = (
              boot_predictions.iloc[i, :] + sample_residuals
          )
  
      if self.transformer_series_[self.level]:
          for col in boot_predictions.columns:
              boot_predictions[col] = transform_series(
                  series=boot_predictions[col],
                  transformer=self.transformer_series_[self.level],
                  fit=False,
                  inverse_transform=True,
              )
  
      return boot_predictions
  
imports: from typing import Union, Dict, List, Tuple, Any, Optional, Callable
  import warnings
  import logging
  import sys
  import numpy
  import pandas
  import sklearn
  import sklearn.pipeline
  from sklearn.base import clone
  from sklearn.preprocessing import StandardScaler
  import inspect
  from copy import copy, deepcopy
  from itertools import chain
  from joblib import Parallel, delayed, cpu_count
  import skforecast
  from ..ForecasterBase import ForecasterBase
  from ..exceptions import IgnoredArgumentWarning
  from ..utils import initialize_lags
  from ..utils import initialize_weights
  from ..utils import check_select_fit_kwargs
  from ..utils import check_y
  from ..utils import check_exog
  from ..utils import get_exog_dtypes
  from ..utils import check_exog_dtypes
  from ..utils import check_predict_input
  from ..utils import check_interval
  from ..utils import preprocess_y
  from ..utils import preprocess_last_window
  from ..utils import preprocess_exog
  from ..utils import exog_to_direct
  from ..utils import exog_to_direct_numpy
  from ..utils import expand_index
  from ..utils import transform_series
  from ..utils import transform_dataframe
  from ..utils import select_n_jobs_fit_forecaster
label_desc: Use image node_id 9 for calling the ForecasterAutoregMultiVariate obj's underlying member method code with example usage: obj.predict_bootstrapping(steps, last_window, exog, n_boot, random_state, in_sample_residuals, levels) and returns: boot_predictions