code: def get_ranks_and_splits(
      grid_search,
      score_func=EvaluationMetricEnum.MeanAbsolutePercentError.name,
      greater_is_better=False,
      combine_splits=True,
      decimals=None,
      warn_metric=True,
  ):
      """Extracts CV results from ``grid_search`` for the specified score function.
      Returns the correct ranks on the test set and a tuple of the scores across splits,
      for both test set and train set (if available).
  
      Notes
      -----
      While ``cv_results`` contains keys with the ranks, these ranks are inverted
      if lower values are better and the ``scoring`` function was initialized
      with ``greater_is_better=True`` to report metrics with their original sign.
  
      This function always returns the correct ranks, accounting for metric direction.
  
      Parameters
      ----------
      grid_search : `~sklearn.model_selection.RandomizedSearchCV`
          Grid search output (fitted RandomizedSearchCV object).
      score_func : `str` or callable, default ``EvaluationMetricEnum.MeanAbsolutePercentError.name``
          Score function to get the ranks for.
          If a callable, takes arrays ``y_true``, ``y_pred`` and returns a float.
          If a string, must be either a
          `~greykite.common.evaluation.EvaluationMetricEnum` member name
          or `~greykite.common.constants.FRACTION_OUTSIDE_TOLERANCE`.
  
          Should be the same as what was passed to
          :py:meth:`~greykite.framework.templates.forecaster.Forecaster.run_forecast_config`,
          or `~greykite.framework.pipeline.pipeline.forecast_pipeline`,
          or `~greykite.framework.pipeline.utils.get_hyperparameter_searcher`.
      greater_is_better : `bool` or None, default False
          True if ``score_func`` is a score function, meaning higher is better,
          and False if it is a loss function, meaning lower is better.
          Must be provided if ``score_func`` is a callable (custom function).
          Ignored if ``score_func`` is a string, because the direction is known.
  
          Used in this function to rank values in the proper direction.
  
          Should be the same as what was passed to
          :py:meth:`~greykite.framework.templates.forecaster.Forecaster.run_forecast_config`,
          or `~greykite.framework.pipeline.pipeline.forecast_pipeline`,
          or `~greykite.framework.pipeline.utils.get_hyperparameter_searcher`.
      combine_splits : `bool`, default True
          Whether to report split scores as a tuple in a single column.
          If True, a single column is returned for all the splits
          of a given metric and train/test set.
          For example, "split_train_score" would contain the values
          (split1_train_score, split2_train_score, split3_train_score)
          as as tuple.
          If False, they are reported in their original columns.
      decimals : `int` or None, default None
          Number of decimal places to round to.
          If decimals is negative, it specifies the number of
          positions to the left of the decimal point.
          If None, does not round.
      warn_metric : `bool`, default True
          Whether to issue a warning if the requested metric is
          not found in the CV results.
  
      Returns
      -------
      ranks_and_splits : `dict`
          Ranks and split scores.
          Dictionary with the following keys:
  
              ``"short_name"`` : `int`
                  Canonical short name for the ``score_func``.
              ``"ranks"`` : `numpy.array`
                  Ranks of the test scores for the ``score_func``,
                  where 1 is the best.
              ``"split_train"`` : `list` [`list` [`float`]]
                  Train split scores. Outer list corresponds to the
                  parameter setting; inner list contains the
                  scores for that parameter setting across all splits.
              ``"split_test"`` : `list` [`list` [`float`]]
                  Test split scores. Outer list corresponds to the
                  parameter setting; inner list contains the
                  scores for that parameter setting across all splits.
      """
      cv_results = grid_search.cv_results_
      (
          _,
          greater_is_better,
          short_name,
      ) = get_score_func_with_aggregation(
          score_func=score_func,  # string or callable
          greater_is_better=greater_is_better,
          # Dummy value, doesn't matter because we ignore the returned `score_func`
          relative_error_tolerance=0.01,
      )
  
      # Warns if the metric is not available
      if f"mean_test_{short_name}" not in cv_results:
          if warn_metric:
              warnings.warn(
                  f"Metric '{short_name}' is not available in the CV results."
              )
          return {
              "short_name": short_name,
              "ranks": None,
              "split_train": None,
              "split_test": None,
          }
  
      # Computes the ranks, using the same tiebreaking method as in sklearn.
      scores = cv_results[f"mean_test_{short_name}"].copy()
      if greater_is_better:
          scores *= -1  # `rankdata` function ranks lowest values first
      ranks = np.asarray(rankdata(scores, method="min"), dtype=np.int32)
  
      # Computes split score columns.
      train_scores = None
      test_scores = None
  
      def round_as_list(split_scores, decimals=None):
          """Rounds `split_scores` to the specified
          `decimals` and returns the result as a list.
  
          Parameters
          ----------
          split_scores : `numpy.array`
               Split scores.
          decimals : `int` or None, default None
              Number of decimal places to round to.
              If decimals is negative, it specifies the number of
              positions to the left of the decimal point.
              If None, does not round.
          Returns
          -------
          split_scores_list : `list` [`float`]
              ``split_scores``, rounded according
              to ``decimals`` and returned as a list.
          """
          if decimals is not None:
              split_scores = split_scores.round(decimals)
          return split_scores.tolist()
  
      if combine_splits:
          # Each sublist contains the scores for split i
          # across all parameter settings.
          test_scores = [
              round_as_list(
                  cv_results[f"split{i}_test_{short_name}"],
                  decimals=decimals,
              )
              for i in range(grid_search.n_splits_)
          ]
          # Makes each sublist contain the scores for a particular
          # parameter setting across all splits.
          test_scores = list(zip(*test_scores))
  
          # Train scores
          if grid_search.return_train_score:
              train_scores = [
                  round_as_list(
                      cv_results[f"split{i}_train_{short_name}"],
                      decimals=decimals,
                  )
                  for i in range(grid_search.n_splits_)
              ]
              train_scores = list(zip(*train_scores))
  
      ranks_and_splits = {
          "short_name": short_name,
          "ranks": ranks,
          "split_train": train_scores,
          "split_test": test_scores,
      }
      return ranks_and_splits
  
file_path: greykite/greykite/framework/utils/result_summary.py
imports: import re
  import warnings
  import numpy
  import pandas
  from scipy.stats import rankdata
  from greykite.common.constants import FRACTION_OUTSIDE_TOLERANCE
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.python_utils import assert_equal
  from greykite.framework.constants import CV_REPORT_METRICS_ALL
  from greykite.framework.pipeline.utils import get_score_func_with_aggregation
label_desc: Use image node_id 1 for calling a global function with example usage: get_ranks_and_splits(grid_search, score_func, greater_is_better, combine_splits, decimals, warn_metric) and returns: ranks_and_splits, dict, split_scores