code: def test_get_flexible_grouping_evaluation(df2):
      """Tests get_flexible_grouping_evaluation function"""
      forecast = UnivariateForecast(
          df2, train_end_date=datetime.datetime(2018, 1, 5)
      )
      # Checks residual quantiles, MSE/median squared error, and coverage
      map_func_dict = {
          "residual": ElementwiseEvaluationMetricEnum.Residual.name,
          "squared_error": ElementwiseEvaluationMetricEnum.SquaredError.name,
          "coverage": ElementwiseEvaluationMetricEnum.Coverage.name,
      }
      agg_kwargs = {
          "residual_mean": pd.NamedAgg(
              column="residual", aggfunc=np.nanmean
          ),
          "residual_q05": pd.NamedAgg(
              column="residual", aggfunc=partial(np.nanquantile, q=0.05)
          ),
          "residual_q95": pd.NamedAgg(
              column="residual", aggfunc=partial(np.nanquantile, q=0.95)
          ),
          "MSE": pd.NamedAgg(
              column="squared_error", aggfunc=np.nanmean
          ),
          "median_squared_error": pd.NamedAgg(
              column="squared_error", aggfunc=np.nanmedian
          ),
          "coverage": pd.NamedAgg(
              column="coverage", aggfunc=np.nanmean
          ),
      }
  
      result = forecast.get_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature="dow",
          groupby_sliding_window_size=None,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
      )
      expected = pd.DataFrame(
          {
              # Only one value per group, so the mean/median/quantiles are the same
              "residual_mean": [0.0, -2.0, 0.0, 2.0, 2.0],
              "residual_q05": [0.0, -2.0, 0.0, 2.0, 2.0],
              "residual_q95": [0.0, -2.0, 0.0, 2.0, 2.0],
              "MSE": [0.0, 4.0, 0.0, 4.0, 4.0],
              "median_squared_error": [0.0, 4.0, 0.0, 4.0, 4.0],
              "coverage": [0.0, 1.0, 1.0, 0.0, 0.0],
          },
          index=pd.Series([1, 2, 3, 4, 5], name="dow"),
      )
      assert_frame_equal(result, expected)
  
      # Equivalent way to specify `map_func_dict` (without autocomplete)
      map_func_dict = {
          "residual": lambda row: ElementwiseEvaluationMetricEnum.Residual.get_metric_func()(
              row[forecast.actual_col], row[forecast.predicted_col]
          ),
          "squared_error": lambda row: ElementwiseEvaluationMetricEnum.SquaredError.get_metric_func()(
              row[forecast.actual_col], row[forecast.predicted_col]
          ),
          "coverage": lambda row: ElementwiseEvaluationMetricEnum.Coverage.get_metric_func()(
              row[forecast.actual_col],
              row[forecast.predicted_lower_col],
              row[forecast.predicted_upper_col],
          ),
      }
      result = forecast.get_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature="dow",
          groupby_sliding_window_size=None,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
      )
      assert_frame_equal(result, expected)
  
      # Equivalent way to specify `map_func_dict` (without autocomplete)
      map_func_dict = {
          "residual": lambda row: row[cst.ACTUAL_COL]
          - row[cst.PREDICTED_COL],
          "squared_error": lambda row: (
              row[cst.ACTUAL_COL] - row[cst.PREDICTED_COL]
          )
          ** 2,
          "coverage": lambda row: 1.0
          if row[cst.PREDICTED_LOWER_COL]
          < row[cst.ACTUAL_COL]
          < row[cst.PREDICTED_UPPER_COL]
          else 0.0,
      }
      result = forecast.get_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature="dow",
          groupby_sliding_window_size=None,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
      )
      assert_frame_equal(result, expected)
  
      # Groupby sliding window
      result = forecast.get_flexible_grouping_evaluation(
          which="train",
          groupby_time_feature=None,
          groupby_sliding_window_size=3,
          groupby_custom_column=None,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
          extend_col_names=False,
      )
      expected = pd.DataFrame(
          {
              "residual_mean": [-1.0, 4 / 3],
              "residual_q05": [-1.9, 0.2],
              "residual_q95": [-0.1, 2.0],
              "MSE": [2.0, 2.0 + 2 / 3],
              "median_squared_error": [2.0, 4.0],
              "coverage": [0.5, 1 / 3],
          },
          index=pd.DatetimeIndex(
              ["2018-01-01", "2018-01-04"], name="ts_downsample"
          ),
      )
      assert_frame_equal(result, expected)
  
      # On test set with custom groupby column
      custom_groups = pd.Series(["val1"], name="value_group").repeat(
          forecast.df_test.shape[0]
      )
      result = forecast.get_flexible_grouping_evaluation(
          which="test",
          groupby_time_feature=None,
          groupby_sliding_window_size=None,
          groupby_custom_column=custom_groups,
          map_func_dict=map_func_dict,
          agg_kwargs=agg_kwargs,
      )
  
      colindex = pd.Index(
          [
              "residual_mean",
              "residual_q05",
              "residual_q95",
              "MSE",
              "median_squared_error",
              "coverage",
          ]
      )
      expected = pd.DataFrame(
          [[0.5, -0.85, 1.85, 2.5, 2.5, 0.5]],
          columns=colindex,
          index=pd.Series(["val1"], name=custom_groups.name),
      )
      assert_frame_equal(result, expected)
  
imports: import datetime
  import math
  import sys
  from functools import partial
  import numpy
  import pandas
  import pytest
  from pandas.testing import assert_frame_equal
  from pandas.testing import assert_series_equal
  from sklearn.pipeline import Pipeline
  from greykite.common import constants
  from greykite.common.evaluation import ElementwiseEvaluationMetricEnum
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.python_utils import assert_equal
  from greykite.common.testing_utils import gen_sliced_df
  from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
  from greykite.framework.output.univariate_forecast import UnivariateForecast
  from greykite.framework.pipeline.utils import get_forecast
  from greykite.sklearn.estimator.prophet_estimator import ProphetEstimator
  from greykite.sklearn.estimator.silverkite_estimator import SilverkiteEstimator
  from greykite.sklearn.estimator.testing_utils import params_component_breakdowns
label_desc: Use image node_id 15 for calling a global function with example usage: test_get_flexible_grouping_evaluation(df2) without return types