class_docstr: Overlap Boolean Rule class in the style of scikit-learn
class_docstr_tok: ["Overlap","Boolean","Rule","class","in","the","style","of","scikit-learn"]
docstr: Fit model to training data.
  
  :param X: Pandas DataFrame containing covariates
  :param y: +1 for Overlap/Support (depending on rules being learned), 0 for
      non-overlap, and -1 for background samples.  Should only contain (+1/0) for
      overlap rules, or (+1/-1) for learning support rules.
docstr_tok: ["Fit","model","to","training","data",".",":","param","X",":","Pandas","DataFrame","containing","covariates",":","param","y",":","+1","for","Overlap\/Support","(","depending","on","rules","being","learned",")",",","0","for","non-overlap",",","and","-1","for","background","samples",".","Should","only","contain","(","+1\/0",")","for","overlap","rules",",","or","(","+1\/-1",")","for","learning","support","rules","."]
code: def fit(self, X: pd.DataFrame, y: Union[np.ndarray, pd.DataFrame]):
      """
      Fit model to training data.
  
      :param X: Pandas DataFrame containing covariates
      :param y: +1 for Overlap/Support (depending on rules being learned), 0 for
          non-overlap, and -1 for background samples.  Should only contain (+1/0) for
          overlap rules, or (+1/-1) for learning support rules.
      """
      if not self.silent:
          self.logger.info(
              "Learning Boolean rule set on DNF form with hamming loss"
          )
  
      # Overlap / Support (y = +1), non-overlap (y = 0), and uniform background (y = -1) samples
      O = np.where(y > 0)[0]
      N = np.where(y == 0)[0]
      U = np.where(y < 0)[0]
      nO = len(O)
      nN = len(N)
      nU = len(U)
  
      # We should always have overlap samples, and either background or non-overlap samples
      # This will throw an error if, for example, all samples are considered to
      # be in the overlap region
      assert nO > 0 and (
          nU > 0 or nN > 0
      ), "Recieved positive samples, but no negative samples for learning Boolean Rules"
      assert nU == 0 or nN == 0
  
      # Initialize with empty and singleton conjunctions, i.e. X plus all-ones feature
      # Feature indicator and conjunction matrices
      z = pd.DataFrame(
          np.eye(X.shape[1], X.shape[1] + 1, 1, dtype=int),
          index=X.columns,
      )
      A = np.hstack((np.ones((X.shape[0], 1), dtype=int), X))
      # Iteration counter
      self.it = 0
      # Formulate master LP
      # Variables
      w = cvx.Variable(A.shape[1], nonneg=True)
      xiO = cvx.Variable(nO, nonneg=True)
      # Objective function (no penalty on empty conjunction)
      lambdas = self.lambda0 + self.lambda1 * z.sum().values
      lambdas[0] = 0
      if nU:
          obj = cvx.Minimize(cvx.sum(A[U, :] @ w) / nU + lambdas @ w)
      elif nN:
          obj = cvx.Minimize(cvx.sum(A[N, :] @ w) / nN + lambdas @ w)
      # Constraints
      # This gets activated for DNF
      constraints = [
          cvx.sum(xiO) <= (1 - self.alpha) * nO,
          xiO + A[O, :] @ w >= 1,
      ]
  
      # Solve problem
      prob = cvx.Problem(obj, constraints)
      prob.solve(verbose=self.verbose, solver=self.solver)
  
      # Extract dual variables
      r = np.zeros_like(y, dtype=float)
      r[O] = -constraints[1].dual_value
      if nU:
          r[U] = 1.0 / nU
      elif nN:
          r[N] = 1.0 / nN
  
      if not self.silent:
          self.logger.info("Initial solve completed")
  
      # Beam search for conjunctions with negative reduced cost
      # Most negative reduced cost among current variables
      UB = np.dot(r, A) + lambdas
      UB = min(UB.min(), 0)
      v, zNew, Anew = beam_search(
          r,
          X,
          self.lambda0,
          self.lambda1,
          K=self.K,
          UB=UB,
          eps=self.eps,
          B=self.B,
          D=self.D,
      )
  
      while (v < -self.eps).any() and (self.it < self.iterMax):
          # Negative reduced costs found
          self.it += 1
  
          if not self.silent:
              self.logger.info(
                  "Iteration: %d, Objective: %.4f"
                  % (self.it, prob.value)
              )
  
          # Add to existing conjunctions
          z = pd.concat([z, zNew], axis=1, ignore_index=True)
          A = np.concatenate((A, Anew), axis=1)
  
          # Reformulate master LP
          # Variables
          w = cvx.Variable(A.shape[1], nonneg=True)
          # Objective function
          lambdas = np.concatenate(
              (lambdas, self.lambda0 + self.lambda1 * zNew.sum().values)
          )
          if nU:
              obj = cvx.Minimize(
                  cvx.sum(A[U, :] @ w) / nU + lambdas @ w
              )
          elif nN:
              obj = cvx.Minimize(
                  cvx.sum(A[N, :] @ w) / nN + lambdas @ w
              )
          # Constraints
          constraints = [
              cvx.sum(xiO) <= (1 - self.alpha) * nO,
              xiO + A[O, :] @ w >= 1,
          ]
          # Solve problem
          prob = cvx.Problem(obj, constraints)
          prob.solve(verbose=self.verbose, solver=self.solver)
  
          # Extract dual variables
          r = np.zeros_like(y, dtype=float)
          r[O] = -constraints[1].dual_value
          if nU:
              r[U] = 1.0 / nU
          elif nN:
              r[N] = 1.0 / nN
  
          # Beam search for conjunctions with negative reduced cost
          # Most negative reduced cost among current variables
          UB = np.dot(r, A) + lambdas
          # print('UB.min():', UB.min())
          UB = min(UB.min(), 0)
          v, zNew, Anew = beam_search(
              r,
              X,
              self.lambda0,
              self.lambda1,
              K=self.K,
              UB=UB,
              eps=self.eps,
              B=self.B,
              D=self.D,
          )
  
      # Save generated conjunctions and coefficients
      self.z = z
      w = w.value
  
      self.w_raw = w
      self.lp_obj_value = prob.value
  
      self.round_(X, y, scoring=self.rounding)
  
imports: import logging
  from typing import Union
  import cvxpy
  import numpy
  import pandas
  from sklearn.metrics import roc_auc_score
  from .beam_search import beam_search
label_desc: Use image node_id 4 for calling the OverlapBooleanRule obj's underlying member method code with example usage: obj.fit(X, y) without return types