class_docstr: Base class for BoostRFA meta-estimator.
  
  Warning: This class should not be used directly. Use derived classes
  instead.
class_docstr_tok: ["Base","class","for","BoostRFA","meta-estimator",".","Warning",":","This","class","should","not","be","used","directly",".","Use","derived","classes","instead","."]
docstr: Fit the RFA algorithm to automatically tune
  the number of selected features.
docstr_tok: ["Fit","the","RFA","algorithm","to","automatically","tune","the","number","of","selected","features","."]
code: def fit(self, X, y, **fit_params):
      """Fit the RFA algorithm to automatically tune
      the number of selected features."""
  
      self.boost_type_ = _check_boosting(self.estimator)
  
      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
              )
          )
  
      # scoring controls the calculation of self.score_history_
      # scoring is used automatically when 'eval_set' is in fit_params
      scoring = "eval_set" in fit_params
      if self.importance_type == "shap_importances":
          if not self.train_importance and not scoring:
              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 scoring
  
      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
      )
  
      if self.min_features_to_select is None:
          if scoring:
              min_features_to_select = 1
          else:
              min_features_to_select = n_features // 2
      else:
          if scoring:
              min_features_to_select = self.min_features_to_select
          else:
              min_features_to_select = (
                  n_features - self.min_features_to_select
              )
  
      if 0.0 < self.step < 1.0:
          step = int(max(1, self.step * n_features))
      else:
          step = int(self.step)
      if step <= 0:
          raise ValueError("Step must be >0.")
  
      self.support_ = np.zeros(n_features, dtype=np.bool)
      self._support = np.ones(n_features, dtype=np.bool)
      self.ranking_ = np.ones(n_features, dtype=np.int)
      self._ranking = np.ones(n_features, dtype=np.int)
      if scoring:
          self.score_history_ = []
          eval_score = np.max if self.greater_is_better else np.min
          best_score = -np.inf if self.greater_is_better else np.inf
  
      while np.sum(self._support) > min_features_to_select:
          # remaining features
          features = np.arange(n_features)[self._support]
  
          # scoring the previous added features
          if scoring and np.sum(self.support_) > 0:
              _fit_params, estimator = self._check_fit_params(
                  fit_params
              )
              with contextlib.redirect_stdout(io.StringIO()):
                  estimator.fit(
                      self._transform(X, inverse=False),
                      y,
                      **_fit_params,
                  )
              score = self._step_score(estimator)
              self.score_history_.append(score)
              if best_score != eval_score([score, best_score]):
                  best_score = score
                  best_support = self.support_.copy()
                  best_ranking = self.ranking_.copy()
                  best_estimator = estimator
  
          # evaluate the remaining features
          _fit_params, _estimator = self._check_fit_params(
              fit_params, inverse=True
          )
          if self.verbose > 1:
              print(
                  "Fitting estimator with {} features".format(
                      self._support.sum()
                  )
              )
          with contextlib.redirect_stdout(io.StringIO()):
              _estimator.fit(
                  self._transform(X, inverse=True), y, **_fit_params
              )
              if self._support.sum() == n_features:
                  all_features_estimator = _estimator
  
          # 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, self._transform(X, inverse=True)
                  )
          ranks = np.argsort(-coefs)  # the rank is inverted
  
          # add the best features
          threshold = min(
              step, np.sum(self._support) - min_features_to_select
          )
  
          # remaining features to test
          self._support[features[ranks][:threshold]] = False
          self._ranking[np.logical_not(self._support)] += 1
          # features tested
          self.support_[features[ranks][:threshold]] = True
          self.ranking_[np.logical_not(self.support_)] += 1
  
      # set final attributes
      _fit_params, self.estimator_ = self._check_fit_params(fit_params)
      if self.verbose > 1:
          print(
              "Fitting estimator with {} features".format(
                  self._support.sum()
              )
          )
      with contextlib.redirect_stdout(io.StringIO()):
          self.estimator_.fit(
              self._transform(X, inverse=False), y, **_fit_params
          )
  
      # compute step score when only min_features_to_select features left
      if scoring:
          score = self._step_score(self.estimator_)
          self.score_history_.append(score)
          if best_score == eval_score([score, best_score]):
              self.support_ = best_support
              self.ranking_ = best_ranking
              self.estimator_ = best_estimator
  
          if len(set(self.score_history_)) == 1:
              self.support_ = np.ones(n_features, dtype=np.bool)
              self.ranking_ = np.ones(n_features, dtype=np.int)
              self.estimator_ = all_features_estimator
      self.n_features_ = self.support_.sum()
  
      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 4 for calling the _RFA obj's underlying member method code with example usage: obj.fit(X, y) and returns: self