class_docstr: Check for performance differences between subgroups of a feature, optionally accounting for a control variable.
  
  The check identifies 'performance biases': large performance difference for a subgroup compared
  to the baseline performance for the full population. It is intended to be used for fairness analyses.
  
  Subgroups are defined by the categories of a 'protected' feature. Numerical features are first binned
  into quantiles, while categorical features are preserved as-is. The baseline score is the overall
  score when all subgroups are combined. You can add conditions to flag performance differences outside
  of given bounds.
  
  Additionally, the analysis may be separated across the categories of a 'control' feature. Numerical
  features are binned and categorical features are re-binned into `max_number` categories. To account
  for the control feature, baseline scores and subgroup scores are be computed within each of its
  categories.
  
  Parameters
  ----------
  protected_feature : Hashable
      Feature evaluated for differences in performance. Numerical features are binned into `max_categories`
      quantiles. Categorical features are not transformed.
  control_feature : Hashable, default: None
      Feature used to group data prior to evaluating performance differences (differences are only
      assessed within the groups defined by this feature). Numerical features are binned into
      `max_categories` quantiles. Categorical features are re-grouped into at most `max_categories`
      groups if necessary.
  scorer : str or Tuple[str, Union[str, Callable]], default: None
      Name of the performance score function to use.
  max_bins : int, default: 10
      Maximum number of categories into which `control_feature` is binned.
  min_subgroup_size : int, default: 5
      Minimum size of a subgroup for which to compute a performance score.
  max_subgroups_per_control_cat_to_display : int, default: 3
      Maximum number of subgroups to display.
  max_control_cat_to_display: int, default: 3
      Maximum number of `control_feature` categories to display.
  n_samples : int, default: 1_000_000
      Number of samples from the dataset to use.
  random_state : int, default: 42
      Random state to use for probability sampling.
class_docstr_tok: ["Check","for","performance","differences","between","subgroups","of","a","feature",",","optionally","accounting","for","a","control","variable",".","The","check","identifies","'performance","biases","'",":","large","performance","difference","for","a","subgroup","compared","to","the","baseline","performance","for","the","full","population",".","It","is","intended","to","be","used","for","fairness","analyses",".","Subgroups","are","defined","by","the","categories","of","a","'protected","'","feature",".","Numerical","features","are","first","binned","into","quantiles",",","while","categorical","features","are","preserved","as-is",".","The","baseline","score","is","the","overall","score","when","all","subgroups","are","combined",".","You","can","add","conditions","to","flag","performance","differences","outside","of","given","bounds",".","Additionally",",","the","analysis","may","be","separated","across","the","categories","of","a","'control","'","feature",".","Numerical","features","are","binned","and","categorical","features","are","re-binned","into","`","max_number","`","categories",".","To","account","for","the","control","feature",",","baseline","scores","and","subgroup","scores","are","be","computed","within","each","of","its","categories",".","Parameters","--","--","--","--","--","protected_feature",":","Hashable","Feature","evaluated","for","differences","in","performance",".","Numerical","features","are","binned","into","`","max_categories","`","quantiles",".","Categorical","features","are","not","transformed",".","control_feature",":","Hashable",",","default",":","None","Feature","used","to","group","data","prior","to","evaluating","performance","differences","(","differences","are","only","assessed","within","the","groups","defined","by","this","feature",")",".","Numerical","features","are","binned","into","`","max_categories","`","quantiles",".","Categorical","features","are","re-grouped","into","at","most","`","max_categories","`","groups","if","necessary",".","scorer",":","str","or","Tuple","[","str",",","Union","[","str",",","Callable","]","]",",","default",":","None","Name","of","the","performance","score","function","to","use",".","max_bins",":","int",",","default",":","10","Maximum","number","of","categories","into","which","`","control_feature","`","is","binned",".","min_subgroup_size",":","int",",","default",":","5","Minimum","size","of","a","subgroup","for","which","to","compute","a","performance","score",".","max_subgroups_per_control_cat_to_display",":","int",",","default",":","3","Maximum","number","of","subgroups","to","display",".","max_control_cat_to_display",":","int",",","default",":","3","Maximum","number","of","`","control_feature","`","categories","to","display",".","n_samples",":","int",",","default",":","1_000_000","Number","of","samples","from","the","dataset","to","use",".","random_state",":","int",",","default",":","42","Random","state","to","use","for","probability","sampling","."]
docstr: Compute performance scores.
  
  Compute performance scores disaggregated by `feature` and `control_feature` categories,
  and averaged over `feature` for each `control_feature` level. Also computes subgroup size.
docstr_tok: ["Compute","performance","scores",".","Compute","performance","scores","disaggregated","by","`","feature","`","and","`","control_feature","`","categories",",","and","averaged","over","`","feature","`","for","each","`","control_feature","`","level",".","Also","computes","subgroup","size","."]
code: def _make_scores_df(
      self, model, dataset, scorer, partitions, model_classes
  ):
      """
      Compute performance scores.
  
      Compute performance scores disaggregated by `feature` and `control_feature` categories,
      and averaged over `feature` for each `control_feature` level. Also computes subgroup size.
      """
      classwise = is_classwise(scorer, model, dataset)
  
      scores_df = expand_grid(**partitions, _scorer=[scorer])
  
      # Get datasets for each subgroup
      scores_df["_dataset"] = scores_df.apply(
          lambda x: combine_filters(x[partitions.keys()], dataset.data),
          axis=1,
      )
  
      def score(data, model, scorer):
          if len(data) < self.min_subgroup_size:
              if classwise:
                  return {cls: np.nan for cls in model_classes}
              else:
                  return np.nan
          return scorer(model, dataset.copy(data))
  
      def apply_scorer(x):
          return score(x["_dataset"], model, x["_scorer"])
  
      # Compute subgroup scores and baseline scores
      scores_df["_score"] = scores_df.apply(apply_scorer, axis=1)
      if self.control_feature is not None:
          control_scores = {
              x.label: score(x.filter(dataset.data), model, scorer)
              for x in scores_df[self.control_feature].unique()
          }
          control_count = {
              x.label: len(x.filter(dataset.data))
              for x in scores_df[self.control_feature].unique()
          }
          scores_df["_baseline"] = scores_df.apply(
              lambda x: control_scores[x[self.control_feature].label],
              axis=1,
          )
          scores_df["_baseline_count"] = scores_df.apply(
              lambda x: control_count[x[self.control_feature].label],
              axis=1,
          )
      else:
          overall_score = score(dataset.data, model, scorer)
          overall_len = len(dataset.data)
          scores_df["_baseline"] = scores_df.apply(
              lambda x: overall_score, axis=1
          )
          scores_df["_baseline_count"] = scores_df.apply(
              lambda x: overall_len, axis=1
          )
  
      # Compute subgroup size
      scores_df["_count"] = scores_df.apply(
          lambda x: len(x["_dataset"]), axis=1
      )
  
      # Replace functions and datasets by their name as a string
      scores_df["_scorer"] = scores_df.apply(
          lambda x: x["_scorer"].name, axis=1
      )
      for col_name in partitions.keys():
          scores_df[col_name] = scores_df.apply(
              lambda x, col_name=col_name: x[col_name].label, axis=1
          )
  
      # Drop subgroup dataset
      scores_df.drop(labels=["_dataset"], axis=1, inplace=True)
  
      # For class-wise prediction, explode the scores to a row per class
      if classwise:
          scores_df.insert(
              len(scores_df.columns) - 3,
              "_class",
              scores_df.apply(lambda x: list(x["_score"]), axis=1),
          )
          scores_df["_score"] = scores_df.apply(
              lambda x: list(x["_score"].values()), axis=1
          )
          scores_df["_baseline"] = scores_df.apply(
              lambda x: list(x["_baseline"].values()), axis=1
          )
  
          # Create a list of dictionaries, one dictionary per row
          rows = []
          indices = []
          for i, row in scores_df.iterrows():
              for score, cls, baseline in zip(
                  row["_score"], row["_class"], row["_baseline"]
              ):
                  new_row = row.to_dict()
                  new_row["_score"] = score
                  new_row["_class"] = cls
                  new_row["_baseline"] = baseline
                  rows.append(new_row)
                  indices.append(i)
  
          # Create a new dataframe from the list of dictionaries
          scores_df = pd.DataFrame(
              rows, columns=scores_df.columns, index=indices
          )
  
      # Ensure consistent types for scores
      scores_df["_score"] = scores_df["_score"].astype(float)
      scores_df["_baseline"] = scores_df["_baseline"].astype(float)
  
      # Sort by performance difference
      scores_df["_diff"] = scores_df["_score"] - scores_df["_baseline"]
      scores_df.sort_values("_diff", inplace=True)
  
      return scores_df
  
imports: import itertools
  from typing import Callable, Dict, Tuple, Union
  import numpy
  import pandas
  import plotly.graph_objects
  from plotly.subplots import make_subplots
  from deepchecks.core import CheckResult, ConditionCategory, ConditionResult
  from deepchecks.core.checks import DatasetKind
  from deepchecks.core.errors import DeepchecksProcessError, DeepchecksValueError
  from deepchecks.tabular import Context, SingleDatasetCheck
  from deepchecks.utils.performance.partition import partition_column
  from deepchecks.utils.typing import Hashable
label_desc: Use image node_id 6 for calling the PerformanceBias obj's underlying member method code with example usage: obj._make_scores_df(model, dataset, scorer, partitions, model_classes) and returns: scores_df, scorer, score, unknown, np