class_docstr: Base class for BoostBoruta meta-estimator.
  
  Warning: This class should not be used directly. Use derived classes
  instead.
  
  Notes
  -----
  The code for the Boruta algorithm is inspired and improved from:
  https://github.com/scikit-learn-contrib/boruta_py
class_docstr_tok: ["Base","class","for","BoostBoruta","meta-estimator",".","Warning",":","This","class","should","not","be","used","directly",".","Use","derived","classes","instead",".","Notes","--","--","-","The","code","for","the","Boruta","algorithm","is","inspired","and","improved","from",":","https",":","\/\/github.com\/scikit-learn-contrib\/boruta_py"]
docstr: Fit the Boruta algorithm to automatically tune
  the number of selected features.
docstr_tok: ["Fit","the","Boruta","algorithm","to","automatically","tune","the","number","of","selected","features","."]
code: def fit(self, X, y, **fit_params):
      """Fit the Boruta algorithm to automatically tune
      the number of selected features."""
  
      self.boost_type_ = _check_boosting(self.estimator)
  
      if self.max_iter < 1:
          raise ValueError("max_iter should be an integer >0.")
  
      if self.perc <= 0 or self.perc > 100:
          raise ValueError(
              "The percentile should be between 0 and 100."
          )
  
      if self.alpha <= 0 or self.alpha > 1:
          raise ValueError("alpha should be between 0 and 1.")
  
      if self.early_stopping_boruta_rounds is None:
          es_boruta_rounds = self.max_iter
      else:
          if self.early_stopping_boruta_rounds < 1:
              raise ValueError(
                  "early_stopping_boruta_rounds should be an integer >0."
              )
          es_boruta_rounds = self.early_stopping_boruta_rounds
  
      importances = ["feature_importances", "shap_importances"]
      if self.importance_type not in importances:
          raise ValueError(
              "importance_type must be one of {}. Get '{}'".format(
                  importances, self.importance_type
              )
          )
  
      if self.importance_type == "shap_importances":
          if not self.train_importance and not "eval_set" in fit_params:
              raise ValueError(
                  "When train_importance is set to False, using "
                  "shap_importances, pass at least a eval_set."
              )
          eval_importance = (
              not self.train_importance and "eval_set" in fit_params
          )
  
      shapes = np.shape(X)
      if len(shapes) != 2:
          raise ValueError("X must be 2D.")
      n_features = shapes[1]
  
      # create mask for user-defined categorical features
      self._cat_support = _get_categorical_support(
          n_features, fit_params
      )
  
      # holds the decision about each feature:
      # default (0); accepted (1); rejected (-1)
      dec_reg = np.zeros(n_features, dtype=np.int)
      dec_history = np.zeros((self.max_iter, n_features), dtype=np.int)
      # counts how many times a given feature was more important than
      # the best of the shadow features
      hit_reg = np.zeros(n_features, dtype=np.int)
      # record the history of the iterations
      imp_history = np.zeros(n_features, dtype=np.float)
      sha_max_history = []
  
      for i in range(self.max_iter):
          if (dec_reg != 0).all():
              if self.verbose > 1:
                  print("All Features analyzed. Boruta stop!")
              break
  
          if self.verbose > 1:
              print("Iteration: {} / {}".format(i + 1, self.max_iter))
  
          self._random_state = np.random.RandomState(i + 1000)
  
          # add shadow attributes, shuffle and train estimator
          self.support_ = dec_reg >= 0
          feat_id_real = np.where(self.support_)[0]
          n_real = feat_id_real.shape[0]
          _fit_params, estimator = self._check_fit_params(
              fit_params, feat_id_real
          )
          estimator.set_params(random_state=i + 1000)
          _X = self._create_X(X, feat_id_real)
          with contextlib.redirect_stdout(io.StringIO()):
              estimator.fit(_X, y, **_fit_params)
  
          # get coefs
          if self.importance_type == "feature_importances":
              coefs = _feature_importances(estimator)
          else:
              if eval_importance:
                  coefs = _shap_importances(
                      estimator, _fit_params["eval_set"][-1][0]
                  )
              else:
                  coefs = _shap_importances(estimator, _X)
  
                  # separate importances of real and shadow features
          imp_sha = coefs[n_real:]
          imp_real = np.zeros(n_features) * np.nan
          imp_real[feat_id_real] = coefs[:n_real]
  
          # get the threshold of shadow importances used for rejection
          imp_sha_max = np.percentile(imp_sha, self.perc)
  
          # record importance history
          sha_max_history.append(imp_sha_max)
          imp_history = np.vstack((imp_history, imp_real))
  
          # register which feature is more imp than the max of shadows
          hit_reg[
              np.where(imp_real[~np.isnan(imp_real)] > imp_sha_max)[0]
          ] += 1
  
          # check if a feature is doing better than expected by chance
          dec_reg = self._do_tests(dec_reg, hit_reg, i + 1)
          dec_history[i] = dec_reg
  
          es_id = i - es_boruta_rounds
          if es_id >= 0:
              if np.equal(dec_history[es_id : (i + 1)], dec_reg).all():
                  if self.verbose > 0:
                      print(
                          "Boruta early stopping at iteration {}".format(
                              i + 1
                          )
                      )
                  break
  
      confirmed = np.where(dec_reg == 1)[0]
      tentative = np.where(dec_reg == 0)[0]
  
      self.support_ = np.zeros(n_features, dtype=np.bool)
      self.ranking_ = np.ones(n_features, dtype=np.int) * 4
      self.n_features_ = confirmed.shape[0]
      self.importance_history_ = imp_history[1:]
  
      if tentative.shape[0] > 0:
          tentative_median = np.nanmedian(
              imp_history[1:, tentative], axis=0
          )
          tentative_low = tentative[
              np.where(tentative_median <= np.median(sha_max_history))[
                  0
              ]
          ]
          tentative_up = np.setdiff1d(tentative, tentative_low)
  
          self.ranking_[tentative_low] = 3
          if tentative_up.shape[0] > 0:
              self.ranking_[tentative_up] = 2
  
      if confirmed.shape[0] > 0:
          self.support_[confirmed] = True
          self.ranking_[confirmed] = 1
  
      if (~self.support_).all():
          raise RuntimeError(
              "Boruta didn't select any feature. Try to increase max_iter or "
              "increase (if not None) early_stopping_boruta_rounds or "
              "decrese perc."
          )
  
      _fit_params, self.estimator_ = self._check_fit_params(fit_params)
      with contextlib.redirect_stdout(io.StringIO()):
          self.estimator_.fit(self.transform(X), y, **_fit_params)
  
      return self
  
imports: import io
  import contextlib
  import warnings
  import numpy
  import scipy
  from copy import deepcopy
  from sklearn.base import clone
  from sklearn.utils.validation import check_is_fitted
  from sklearn.base import BaseEstimator, TransformerMixin
  from joblib import Parallel, delayed
  from hyperopt import fmin, tpe
  from .utils import ParameterSampler, _check_param, _check_boosting
  from .utils import _set_categorical_indexes, _get_categorical_support
  from .utils import _feature_importances, _shap_importances
label_desc: Use image node_id 5 for calling the _Boruta obj's underlying member method code with example usage: obj.fit(X, y) and returns: self