docstr: While time allows, repeatedly compute feature importance and generate candidate feature subsets using a fixed time budget.
  If at least self.min_prune_ratio of the features can be pruned or all feature importances are calculated, return. If less than
  self.min_prune_ratio of the features can be pruned but not all importance scores have been calculated, repeat the procedure.
  Note: If we have feature importance information from previously fitted model, make use of them since we might not have time this
  iteration to evaluate importance scores for all features. Any feature importance calculated within this call of compute_next_candidate
  will override previous feature importance info.
docstr_tok: ["While","time","allows",",","repeatedly","compute","feature","importance","and","generate","candidate","feature","subsets","using","a","fixed","time","budget",".","If","at","least","self.min_prune_ratio","of","the","features","can","be","pruned","or","all","feature","importances","are","calculated",",","return",".","If","less","than","self.min_prune_ratio","of","the","features","can","be","pruned","but","not","all","importance","scores","have","been","calculated",",","repeat","the","procedure",".","Note",":","If","we","have","feature","importance","information","from","previously","fitted","model",",","make","use","of","them","since","we","might","not","have","time","this","iteration","to","evaluate","importance","scores","for","all","features",".","Any","feature","importance","calculated","within","this","call","of","compute_next_candidate","will","override","previous","feature","importance","info","."]
code: def compute_next_candidate(
      self,
      fn_args: dict,
      round_time_budget: float,
      prev_best_features: List[str],
      prev_importance_df: pd.DataFrame,
  ) -> Tuple[List[str], pd.DataFrame, bool, float]:
      """
      While time allows, repeatedly compute feature importance and generate candidate feature subsets using a fixed time budget.
      If at least self.min_prune_ratio of the features can be pruned or all feature importances are calculated, return. If less than
      self.min_prune_ratio of the features can be pruned but not all importance scores have been calculated, repeat the procedure.
      Note: If we have feature importance information from previously fitted model, make use of them since we might not have time this
      iteration to evaluate importance scores for all features. Any feature importance calculated within this call of compute_next_candidate
      will override previous feature importance info.
      """
      candidate_features = prev_best_features
      importance_df = unevaluated_fi_df_template(candidate_features)
      candidate_found = False
      total_prune_time = 0.0
      # mark previous fit's computed feature importances here.
      if prev_importance_df is not None:
          fn_args["prev_importance_df"] = prev_importance_df
          fn_args["using_prev_fit_fi"] = set(
              prev_importance_df[
                  prev_importance_df["n"] > 0
              ].index.tolist()
          )
      while (
          self.time_limit - (time.time() - self.time_start)
          > round_time_budget + self.fit_score_time
      ):
          (
              candidate_features,
              importance_df,
              prune_time,
          ) = self.compute_next_candidate_round(**fn_args)
          # HACK: Line below is needed to get this working with n-repeated bagged models. Related to feature ordering.
          candidate_features = [
              feature
              for feature in fn_args["X"].columns.tolist()
              if feature in candidate_features
          ]
          candidate_found = len(candidate_features) > 0 and len(
              candidate_features
          ) <= (1.0 - self.min_prune_ratio) * len(prev_best_features)
          all_features_evaluated = (
              len(importance_df[importance_df["importance"].isna()])
              == 0
          )
          fn_args["prev_importance_df"] = importance_df
          total_prune_time = total_prune_time + prune_time
          if candidate_found or all_features_evaluated:
              break
      logger.log(
          15,
          f"\tCandidate generation time: ({round(total_prune_time, 2)}s), Cardinality: {len(candidate_features)}",
      )
      return (
          candidate_features,
          importance_df,
          candidate_found,
          total_prune_time,
      )
  
imports: import logging
  import time
  import traceback
  import uuid
  from copy import deepcopy
  from typing import List, Set, Tuple, Union
  import numpy
  import pandas
  from autogluon.common.features.types import R_FLOAT
  from ..models.abstract.abstract_model import AbstractModel
  from ..models.ensemble.bagged_ensemble_model import BaggedEnsembleModel
  from ..utils.exceptions import TimeLimitExceeded
  from ..utils.utils import generate_train_test_split, unevaluated_fi_df_template
label_desc: Use image node_id 3 for calling the FeatureSelector obj's underlying member method code with example usage: obj.compute_next_candidate(fn_args, round_time_budget, prev_best_features, prev_importance_df) and returns: candidate_features,  importance_df,  candidate_found,  total_prune_time