class_docstr: Implements the strategy of stopping a trial if its performance
  falls below that of other trials at the same step.
class_docstr_tok: ["Implements","the","strategy","of","stopping","a","trial","if","its","performance","falls","below","that","of","other","trials","at","the","same","step","."]
docstr: Stop a trial if its performance is in the bottom `percentile_threshold`
  of the trials at the same step.
  
  Args:
      trial_index: Indices of candidate trial to stop early.
      experiment: Experiment that contains the trials and other contextual data.
      df: Dataframe of partial results after applying interpolation,
          filtered to objective metric.
      df_raw: The original MapData dataframe (before interpolation).
      map_key: Name of the column of the dataset that indicates progression.
      minimize: Whether objective value is being minimized.
  
  Returns:
      A tuple `(should_stop, reason)`, where `should_stop` is `True` iff the
      trial should be stopped, and `reason` is an (optional) string providing
      information on why the trial should or should not be stopped.
docstr_tok: ["Stop","a","trial","if","its","performance","is","in","the","bottom","`","percentile_threshold","`","of","the","trials","at","the","same","step",".","Args",":","trial_index",":","Indices","of","candidate","trial","to","stop","early",".","experiment",":","Experiment","that","contains","the","trials","and","other","contextual","data",".","df",":","Dataframe","of","partial","results","after","applying","interpolation",",","filtered","to","objective","metric",".","df_raw",":","The","original","MapData","dataframe","(","before","interpolation",")",".","map_key",":","Name","of","the","column","of","the","dataset","that","indicates","progression",".","minimize",":","Whether","objective","value","is","being","minimized",".","Returns",":","A","tuple","`","(","should_stop",",","reason",")","`",",","where","`","should_stop","`","is","`","True","`","iff","the","trial","should","be","stopped",",","and","`","reason","`","is","an","(","optional",")","string","providing","information","on","why","the","trial","should","or","should","not","be","stopped","."]
code: def should_stop_trial_early(
      self,
      trial_index: int,
      experiment: Experiment,
      df: pd.DataFrame,
      df_raw: pd.DataFrame,
      map_key: str,
      minimize: bool,
  ) -> Tuple[bool, Optional[str]]:
      """Stop a trial if its performance is in the bottom `percentile_threshold`
      of the trials at the same step.
  
      Args:
          trial_index: Indices of candidate trial to stop early.
          experiment: Experiment that contains the trials and other contextual data.
          df: Dataframe of partial results after applying interpolation,
              filtered to objective metric.
          df_raw: The original MapData dataframe (before interpolation).
          map_key: Name of the column of the dataset that indicates progression.
          minimize: Whether objective value is being minimized.
  
      Returns:
          A tuple `(should_stop, reason)`, where `should_stop` is `True` iff the
          trial should be stopped, and `reason` is an (optional) string providing
          information on why the trial should or should not be stopped.
      """
      logger.info(
          f"Considering trial {trial_index} for early stopping."
      )
  
      stopping_eligible, reason = self.is_eligible(
          trial_index=trial_index,
          experiment=experiment,
          df=df_raw,
          map_key=map_key,
      )
      if not stopping_eligible:
          return False, reason
  
      # dropna() here will exclude trials that have not made it to the
      # last progression of the trial under consideration, and therefore
      # can't be included in the comparison
      df_trial = not_none(df[trial_index].dropna())
      trial_last_prog = df_trial.index.max()
      data_at_last_progression = df.loc[trial_last_prog].dropna()
      logger.info(
          "Early stopping objective at last progression is:\n"
          f"{data_at_last_progression}."
      )
  
      # check for enough number of trials with data
      if (
          self.min_curves is not None
          and len(data_at_last_progression)
          < self.min_curves  # pyre-ignore[58]
      ):
          return self._log_and_return_num_trials_with_data(
              logger=logger,
              trial_index=trial_index,
              trial_last_progression=trial_last_prog,
              num_trials_with_data=len(data_at_last_progression),
              min_curves=self.min_curves,  # pyre-ignore[6]
          )
  
      # percentile early stopping logic
      percentile_threshold = (
          100.0 - self.percentile_threshold
          if minimize
          else self.percentile_threshold
      )
      percentile_value = np.percentile(
          data_at_last_progression, percentile_threshold
      )
      trial_objective_value = data_at_last_progression[trial_index]
      should_early_stop = (
          trial_objective_value > percentile_value
          if minimize
          else trial_objective_value < percentile_value
      )
      comp = "worse" if should_early_stop else "better"
      reason = (
          f"Trial objective value {trial_objective_value} is {comp} than "
          f"{percentile_threshold:.1f}-th percentile ({percentile_value}) "
          "across comparable trials."
      )
      logger.info(
          f"Early stopping decision for {trial_index}: {should_early_stop}. "
          f"Reason: {reason}"
      )
      return should_early_stop, reason
  
file_path: Ax/ax/early_stopping/strategies/percentile.py
imports: from logging import Logger
  from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
  import numpy
  import pandas
  from ax.core.experiment import Experiment
  from ax.early_stopping.strategies.base import BaseEarlyStoppingStrategy
  from ax.early_stopping.utils import align_partial_results
  from ax.exceptions.core import UnsupportedError
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import not_none
label_desc: Use image node_id 3 for calling the PercentileEarlyStoppingStrategy obj's underlying member method code with example usage: obj.should_stop_trial_early(trial_index, experiment, df, df_raw, map_key, minimize) and returns: should_early_stop,  reason, False,  reason, self