class_docstr: Operations related to the Lagrangian.
  
  Parameters
  ----------
  X : {numpy.ndarray, pandas.DataFrame}
      the training features
  sensitive_features : {numpy.ndarray, pandas.Series, pandas.DataFrame, list}
      the sensitive features to use for constraints
  y : {numpy.ndarray, pandas.Series, pandas.DataFrame, list}
      the training labels
  estimator :
      the estimator to fit in every iteration of :meth:`best_h` using a
      :meth:`fit` method with arguments `X`, `y`, and `sample_weight`
  constraints : fairlearn.reductions.Moment
      Object describing the fairness constraints. This provides the reweighting
      and relabelling.
  objective : fairlearn.reductions.Moment
      Object describing the optimization objective. The default is :code:`ErrorRate()` for
      binary classification and :code:`MeanLoss(...)` for regression.
  B : float
      bound on the L1-norm of the lambda vector
  opt_lambda : bool
      indicates whether to optimize lambda during the calculation of the
      Lagrangian; optional with default value True
  sample_weight_name : str
      Name of the argument to `estimator.fit()` which supplies the sample weights
      (defaults to `sample_weight`)
docstr: Solve the best-response problem.
  
  Returns the classifier that solves the best-response problem for
  the vector of Lagrange multipliers `lambda_vec`.
docstr_tok: ["Solve","the","best-response","problem",".","Returns","the","classifier","that","solves","the","best-response","problem","for","the","vector","of","Lagrange","multipliers","`","lambda_vec","`","."]
code: def best_h(self, lambda_vec):
      """Solve the best-response problem.
  
      Returns the classifier that solves the best-response problem for
      the vector of Lagrange multipliers `lambda_vec`.
      """
      classifier = self._call_oracle(lambda_vec)
  
      h = _PredictorAsCallable(classifier)
  
      h_error = self.obj.gamma(h).iloc[0]
      h_gamma = self.constraints.gamma(h)
      h_value = h_error + h_gamma.dot(lambda_vec)
  
      if not self.hs.empty:
          values = self.errors + self.gammas.transpose().dot(lambda_vec)
          best_idx = values.idxmin()
          best_value = values[best_idx]
      else:
          best_idx = -1
          best_value = np.PINF
  
      if h_value < best_value - _PRECISION:
          logger.debug(
              "%sbest_h: val improvement %f",
              _LINE,
              best_value - h_value,
          )
          h_idx = len(self.hs)
          self.hs.at[h_idx] = h
          self.predictors.at[h_idx] = classifier
          self.errors.at[h_idx] = h_error
          self.gammas[h_idx] = h_gamma
          self.lambdas[h_idx] = lambda_vec.copy()
          best_idx = h_idx
  
      return self.hs[best_idx], best_idx
  
imports: import logging
  from time import time
  import numpy
  import pandas
  import scipy.optimize
  from sklearn import clone
  from sklearn.dummy import DummyClassifier
  from fairlearn.reductions._moments import ClassificationMoment
  from ._constants import _INDENTATION, _LINE, _PRECISION
label_desc: Use image node_id 6 for calling the _Lagrangian obj's underlying member method code with example usage: obj.best_h(lambda_vec) and returns: self,  best_idx