docstr: Having previously computed the aggregates and the distinct q thresholds
  to consider in the get_aggregates function,we are now ready to choose the best
  subset of attribute values for the given attribute.
  For each range defined by these thresholds, we will choose all of the positive contributions,
  compute the MLE value of q, and the corresponding score.
  We then pick the best q and score over all of the ranges considered.
  
  :param aggregates: dictionary of aggregates. For each feature value, it has q_mle, q_min, q_max, observed_sum,
  and the expectations
  :param thresholds: sorted thresholds (roots)
  :param penalty: penalty coefficient
  :param all_observed_sum: sum of observed binary outcomes for all i
  :param all_expectations: data series containing all the expectations/expected outcomes
  :return:
docstr_tok: ["Having","previously","computed","the","aggregates","and","the","distinct","q","thresholds","to","consider","in","the","get_aggregates","function",",","we","are","now","ready","to","choose","the","best","subset","of","attribute","values","for","the","given","attribute",".","For","each","range","defined","by","these","thresholds",",","we","will","choose","all","of","the","positive","contributions",",","compute","the","MLE","value","of","q",",","and","the","corresponding","score",".","We","then","pick","the","best","q","and","score","over","all","of","the","ranges","considered",".",":","param","aggregates",":","dictionary","of","aggregates",".","For","each","feature","value",",","it","has","q_mle",",","q_min",",","q_max",",","observed_sum",",","and","the","expectations",":","param","thresholds",":","sorted","thresholds","(","roots",")",":","param","penalty",":","penalty","coefficient",":","param","all_observed_sum",":","sum","of","observed","binary","outcomes","for","all","i",":","param","all_expectations",":","data","series","containing","all","the","expectations\/expected","outcomes",":","return",":"]
code: def choose_aggregates(
      self,
      aggregates: dict,
      thresholds: list,
      penalty: float,
      all_observed_sum: float,
      all_expectations: list,
  ):
      """
      Having previously computed the aggregates and the distinct q thresholds
      to consider in the get_aggregates function,we are now ready to choose the best
      subset of attribute values for the given attribute.
      For each range defined by these thresholds, we will choose all of the positive contributions,
      compute the MLE value of q, and the corresponding score.
      We then pick the best q and score over all of the ranges considered.
  
      :param aggregates: dictionary of aggregates. For each feature value, it has q_mle, q_min, q_max, observed_sum,
      and the expectations
      :param thresholds: sorted thresholds (roots)
      :param penalty: penalty coefficient
      :param all_observed_sum: sum of observed binary outcomes for all i
      :param all_expectations: data series containing all the expectations/expected outcomes
      :return:
      """
      # initialize
      best_score = 0
      best_names = []
  
      scoring_function = self.scoring_function
  
      # for each threshold
      for i in range(len(thresholds) - 1):
          threshold = (thresholds[i] + thresholds[i + 1]) / 2
          observed_sum = 0.0
          expectations = []
          names = []
  
          # keep only the aggregates which have a positive contribution to the score in that q range
          # we must keep track of the sum of outcome values as well as all predicted expectations
          for key, value in aggregates.items():
              if (value["q_min"] < threshold) & (
                  value["q_max"] > threshold
              ):
                  names.append(key)
                  observed_sum += value["observed_sum"]
                  expectations = (
                      expectations + value["expectations"].tolist()
                  )
  
          if len(expectations) == 0:
              continue
  
          # compute the MLE value of q, making sure to only consider the desired direction (positive or negative)
          expectations = np.asarray(expectations)
          current_q_mle = scoring_function.qmle(
              observed_sum, expectations
          )
  
          # Compute the score for the given subset at the MLE value of q.
          # Notice that each included value gets a penalty, so the total penalty
          # is multiplied by the number of included values.
          current_interval_score = scoring_function.score(
              observed_sum,
              expectations,
              penalty * len(names),
              current_q_mle,
          )
  
          # keep track of the best score, best q, and best subset of attribute values found so far
          if current_interval_score > best_score:
              best_score = current_interval_score
              best_names = names
  
      # Now we also have to consider the case of including all attribute values,
      # including those that never make positive contributions to the score.
      # Note that the penalty term is 0 in this case.  (We are neglecting penalties
      # from all other attributes, just considering the current attribute.)
  
      # compute the MLE value of q, making sure to only consider the desired direction (positive or negative)
      current_q_mle = scoring_function.qmle(
          all_observed_sum, all_expectations
      )
  
      # Compute the score for the given subset at the MLE value of q.
      # Again, the penalty (for that attribute) is 0 when all attribute values are included.
  
      current_score = scoring_function.score(
          all_observed_sum, all_expectations, 0, current_q_mle
      )
  
      # Keep track of the best score, best q, and best subset of attribute values found.
      # Note that if the best subset contains all values of the given attribute,
      # we return an empty list for best_names.
      if current_score > best_score:
          best_score = current_score
          best_names = []
  
      return [best_names, best_score]
  
file_path: AIF360/aif360/detectors/mdss/MDSS.py
imports: from aif360.detectors.mdss.ScoringFunctions.ScoringFunction import ScoringFunction
  from aif360.detectors.mdss.generator import get_entire_subset, get_random_subset
  from aif360.detectors.mdss.ScoringFunctions import Bernoulli, BerkJones, Gaussian, ScoringFunction, Poisson
  import pandas
  import numpy
label_desc: Use image node_id 3 for calling the MDSS obj's underlying member method code with example usage: obj.choose_aggregates(aggregates, thresholds, penalty, all_observed_sum, all_expectations) and returns: list