class_docstr: A generic moment for parity in utilities (or costs) under classification.
  
  This serves as the base class for :class:`DemographicParity`,
  :class:`EqualizedOdds`, and others. All subclasses can be used as
  difference-based constraints or ratio-based constraints.
  Refer to the :ref:`user guide <constraints_binary_classification>` for
  more information and example usage.
  
  Constraints compare the group-level mean utility for each group with the
  overall mean utility (unless further events are specified, e.g., in
  equalized odds).
  Constraint violation for difference-based constraints starts if the
  difference between a group and the overall population with regard to a
  utility exceeds `difference_bound`. For ratio-based constraints, the ratio
  between the group-level and overall mean utility needs to be bounded
  between `ratio_bound` and its inverse (plus an additional additive
  `ratio_bound_slack`).
  
  The `index` field is a :class:`pandas:pandas.MultiIndex` corresponding to
  the constraint IDs.
  It is an index of various DataFrame and Series objects that are either
  required as arguments or returned by several of the methods of the
  `UtilityParity` class. It is the Cartesian product of:
  
  - The unique events defining the particular moment object
  - The unique values of the sensitive feature
  - The characters `+` and `-`, corresponding to the Lagrange multipliers
    for positive and negative violations of the constraint
  
  Read more in the :ref:`User Guide <constraints_binary_classification>`.
  
  Parameters
  ----------
  difference_bound : float
      The constraints' difference bound for constraints that are expressed
      as differences, also referred to as :math:`\\epsilon` in documentation.
      If `ratio_bound` is used then `difference_bound` needs to be None.
      If neither `ratio_bound` nor `difference_bound` are set then a default
      difference bound of 0.01 is used for backwards compatibility.
      Default None.
  ratio_bound : float
      The constraints' ratio bound for constraints that are expressed as
      ratios. The specified value needs to be in (0,1].
      If `difference_bound` is used then `ratio_bound` needs to be None.
      Default None.
  ratio_bound_slack : float
      The constraints' ratio bound slack for constraints that are
      expressed as ratios, also referred to as :math:`\\epsilon` in
      documentation.
      `ratio_bound_slack` is ignored if `ratio_bound` is not specified.
      Default 0.0
class_docstr_tok: ["A","generic","moment","for","parity","in","utilities","(","or","costs",")","under","classification",".","This","serves","as","the","base","class","for",":","class",":","`","DemographicParity","`",",",":","class",":","`","EqualizedOdds","`",",","and","others",".","All","subclasses","can","be","used","as","difference-based","constraints","or","ratio-based","constraints",".","Refer","to","the",":","ref",":","`","user","guide","<","constraints_binary_classification",">","`","for","more","information","and","example","usage",".","Constraints","compare","the","group-level","mean","utility","for","each","group","with","the","overall","mean","utility","(","unless","further","events","are","specified",",","e.g.",",","in","equalized","odds",")",".","Constraint","violation","for","difference-based","constraints","starts","if","the","difference","between","a","group","and","the","overall","population","with","regard","to","a","utility","exceeds","`","difference_bound","`",".","For","ratio-based","constraints",",","the","ratio","between","the","group-level","and","overall","mean","utility","needs","to","be","bounded","between","`","ratio_bound","`","and","its","inverse","(","plus","an","additional","additive","`","ratio_bound_slack","`",")",".","The","`","index","`","field","is","a",":","class",":","`","pandas",":","pandas.MultiIndex","`","corresponding","to","the","constraint","IDs",".","It","is","an","index","of","various","DataFrame","and","Series","objects","that","are","either","required","as","arguments","or","returned","by","several","of","the","methods","of","the","`","UtilityParity","`","class",".","It","is","the","Cartesian","product","of",":","-","The","unique","events","defining","the","particular","moment","object","-","The","unique","values","of","the","sensitive","feature","-","The","characters","`","+","`","and","`","-","`",",","corresponding","to","the","Lagrange","multipliers","for","positive","and","negative","violations","of","the","constraint","Read","more","in","the",":","ref",":","`","User","Guide","<","constraints_binary_classification",">","`",".","Parameters","--","--","--","--","--","difference_bound",":","float","The","constraints","'","difference","bound","for","constraints","that","are","expressed","as","differences",",","also","referred","to","as",":","math",":","`","\\\\epsilon","`","in","documentation",".","If","`","ratio_bound","`","is","used","then","`","difference_bound","`","needs","to","be","None",".","If","neither","`","ratio_bound","`","nor","`","difference_bound","`","are","set","then","a","default","difference","bound","of","0.01","is","used","for","backwards","compatibility",".","Default","None",".","ratio_bound",":","float","The","constraints","'","ratio","bound","for","constraints","that","are","expressed","as","ratios",".","The","specified","value","needs","to","be","in","(","0,1","]",".","If","`","difference_bound","`","is","used","then","`","ratio_bound","`","needs","to","be","None",".","Default","None",".","ratio_bound_slack",":","float","The","constraints","'","ratio","bound","slack","for","constraints","that","are","expressed","as","ratios",",","also","referred","to","as",":","math",":","`","\\\\epsilon","`","in","documentation",".","`","ratio_bound_slack","`","is","ignored","if","`","ratio_bound","`","is","not","specified",".","Default","0.0"]
docstr: Load the specified data into this object.
  
  This adds a column `event` to the `tags` field.
  
  The `utilities` is a 2-d array which corresponds to g(X,A,Y,h(X))
  from :footcite:t:`agarwal2018reductions`.
  The `utilities` defaults to h(X), i.e. [0, 1] for each X_i.
  The first column is G^0 and the second is G^1.
  Assumes binary classification with labels 0/1.
  
  .. math::
      utilities = [g(X,A,Y,h(X)=0), g(X,A,Y,h(X)=1)]
docstr_tok: ["Load","the","specified","data","into","this","object",".","This","adds","a","column","`","event","`","to","the","`","tags","`","field",".","The","`","utilities","`","is","a","2-d","array","which","corresponds","to","g","(","X",",","A",",","Y",",","h","(","X",")",")","from",":","footcite",":","t",":","`","agarwal2018reductions","`",".","The","`","utilities","`","defaults","to","h","(","X",")",",","i.e",".","[","0",",","1","]","for","each","X_i",".","The","first","column","is","G^0","and","the","second","is","G^1",".","Assumes","binary","classification","with","labels","0\/1",".","..","math",":",":","utilities","=","[","g","(","X",",","A",",","Y",",","h","(","X",")","=0",")",",","g","(","X",",","A",",","Y",",","h","(","X",")","=1",")","]"]
code: def load_data(
      self,
      X,
      y: pd.Series,
      *,
      sensitive_features: pd.Series,
      event: pd.Series = None,
      utilities=None,
  ):
      """Load the specified data into this object.
  
      This adds a column `event` to the `tags` field.
  
      The `utilities` is a 2-d array which corresponds to g(X,A,Y,h(X))
      from :footcite:t:`agarwal2018reductions`.
      The `utilities` defaults to h(X), i.e. [0, 1] for each X_i.
      The first column is G^0 and the second is G^1.
      Assumes binary classification with labels 0/1.
  
      .. math::
          utilities = [g(X,A,Y,h(X)=0), g(X,A,Y,h(X)=1)]
  
      """
      super().load_data(X, y, sensitive_features=sensitive_features)
      self.tags[_EVENT] = event
      if utilities is None:
          utilities = np.vstack(
              [
                  np.zeros(y.shape, dtype=np.float64),
                  np.ones(y.shape, dtype=np.float64),
              ]
          ).T
      self.utilities = utilities
      self.utility_diff = self.utilities[:, 1] - self.utilities[:, 0]
      self.prob_event = (
          self.tags.groupby(_EVENT).size() / self.total_samples
      )
      self.prob_group_event = (
          self.tags.groupby([_EVENT, _GROUP_ID]).size()
          / self.total_samples
      )
      signed = pd.concat(
          [self.prob_group_event, self.prob_group_event],
          keys=["+", "-"],
          names=[_SIGN, _EVENT, _GROUP_ID],
      )
      self.index = signed.index
      self.default_objective_lambda_vec = None
  
      # Fill information about the matrix U, which is used to calculate signed weights
      # and gamma vector. The matrix has a row corresponding to each example and column
      # corresponding to each component of lambda, the signed weights and gamma are
      # calculated as:
      #
      # signed_weights = utility_diff * U.dot(lambda_vec)
      # gamma = -U.T.dot(utilities[y_pred]) / total_samples
      #
      # If the i-th example's event and group are "e" and "g" then the entries in the
      # i-th row of the matrix, indexed by tuples (sign, event, group), are defined as:
      #
      # U_i,(+,e',g') =      1[e=e']/P(e) - rho*1[e=e',g=g']/P(g,e)
      # U_i,(-,e',g') = -rho*1[e=e']/P(e) +     1[e=e',g=g']/P(g,e)
      #
      # This corresponds to the expression given right above Theorem 1 of the paper
      # "A Reductions Approach to Fair Classification" by Agarwal et al. (2018).
  
      self.U = pd.DataFrame(
          0, index=self.tags.index, columns=self.index
      )
      for e, g in self.prob_group_event.index:
          event_select = 1 * (self.tags[_EVENT] == e)
          group_event_select = event_select * (
              self.tags[_GROUP_ID] == g
          )
          self.U["+", e, g] = (
              event_select / self.prob_event[e]
              + (-self.ratio)
              * group_event_select
              / self.prob_group_event[e, g]
          )
          self.U["-", e, g] = (
              -self.ratio
          ) * event_select / self.prob_event[
              e
          ] + group_event_select / self.prob_group_event[
              e, g
          ]
  
      # fill in the information about the basis
      event_vals = self.tags[_EVENT].dropna().unique()
      group_vals = self.tags[_GROUP_ID].unique()
      # The matrices pos_basis and neg_basis contain a lower-dimensional description of
      # constraints, which is achieved by removing some redundant constraints.
      # Considering fewer constraints is not required for correctness, but it can dramatically
      # speed up GridSearch.
      self.pos_basis = pd.DataFrame()
      self.neg_basis = pd.DataFrame()
      self.neg_basis_present = pd.Series(dtype="float64")
      zero_vec = pd.Series(0.0, self.index)
      i = 0
      for e in event_vals:
          # Constraints on the final group are redundant, so they are not included in the basis.
          for g in group_vals[:-1]:
              self.pos_basis[i] = 0 + zero_vec
              self.neg_basis[i] = 0 + zero_vec
              self.pos_basis[i]["+", e, g] = 1
              self.neg_basis[i]["-", e, g] = 1
              self.neg_basis_present.at[i] = True
              i += 1
  
imports: import numpy
  import pandas
  from fairlearn.utils._input_validation import _MESSAGE_RATIO_NOT_IN_RANGE, _validate_and_reformat_input
  from .error_rate import ErrorRate
  from .moment import _ALL, _EVENT, _GROUP_ID, _LABEL, _SIGN, ClassificationMoment
label_desc: Use image node_id 3 for calling the UtilityParity obj's underlying member method code with example usage: obj.load_data(X, y) without return types