class_docstr: BooleanRuleCG is a directly interpretable supervised learning method
  for binary classification that learns a Boolean rule in disjunctive
  normal form (DNF) or conjunctive normal form (CNF) using column generation (CG).
  AIX360 implements a heuristic beam search version of BRCG that is less 
  computationally intensive than the published integer programming version [#NeurIPS2018]_.
  
  References:
      .. [#NeurIPS2018] `S. Dash, O. Günlük, D. Wei, "Boolean decision rules via
         column generation." Neural Information Processing Systems (NeurIPS), 2018.
         <https://papers.nips.cc/paper/7716-boolean-decision-rules-via-column-generation.pdf>`_
docstr: Fit model to training data.
  
  Args:
      X (DataFrame): Binarized features with MultiIndex column labels
      y (array): Binary-valued target variable
  Returns:
      BooleanRuleCG: Self
docstr_tok: ["Fit","model","to","training","data",".","Args",":","X","(","DataFrame",")",":","Binarized","features","with","MultiIndex","column","labels","y","(","array",")",":","Binary-valued","target","variable","Returns",":","BooleanRuleCG",":","Self"]
code: def fit(self, X, y):
      """Fit model to training data.
  
      Args:
          X (DataFrame): Binarized features with MultiIndex column labels
          y (array): Binary-valued target variable
      Returns:
          BooleanRuleCG: Self
      """
      if not self.silent:
          print(
              "Learning {} rule with complexity parameters lambda0={}, lambda1={}".format(
                  "CNF" if self.CNF else "DNF",
                  self.lambda0,
                  self.lambda1,
              )
          )
      if self.CNF:
          # Flip labels for CNF
          y = 1 - y
      # Positive (y = 1) and negative (y = 0) samples
      P = np.where(y > 0.5)[0]
      Z = np.where(y < 0.5)[0]
      nP = len(P)
      n = len(y)
  
      # 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
      # Start time
      self.starttime = time.time()
  
      # Formulate master LP
      # Variables
      w = cvx.Variable(A.shape[1], nonneg=True)
      xi = cvx.Variable(nP, nonneg=True)
      # Objective function (no penalty on empty conjunction)
      cs = self.lambda0 + self.lambda1 * z.sum().values
      cs[0] = 0
      obj = cvx.Minimize(
          cvx.sum(xi) / n + cvx.sum(A[Z, :] * w) / n + cs * w
      )
      # Constraints
      constraints = [xi + A[P, :] * w >= 1]
  
      # Solve problem
      prob = cvx.Problem(obj, constraints)
      prob.solve(solver=self.solver, verbose=self.verbose)
      if not self.silent:
          print("Initial LP solved")
  
      # Extract dual variables
      r = np.ones_like(y, dtype=float) / n
      r[P] = -constraints[0].dual_value
  
      # Beam search for conjunctions with negative reduced cost
      # Most negative reduced cost among current variables
      UB = np.dot(r, A) + cs
      UB = min(UB.min(), 0)
      v, zNew, Anew = beam_search(
          r,
          X,
          self.lambda0,
          self.lambda1,
          K=self.K,
          UB=UB,
          D=self.D,
          B=self.B,
          eps=self.eps,
      )
  
      while (
          (v < -self.eps).any()
          and (self.it < self.iterMax)
          and (time.time() - self.starttime < self.timeMax)
      ):
          # Negative reduced costs found
          self.it += 1
          if not self.silent:
              print(
                  "Iteration: {}, Objective: {:.4f}".format(
                      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
          cs = np.concatenate(
              (cs, self.lambda0 + self.lambda1 * zNew.sum().values)
          )
          obj = cvx.Minimize(
              cvx.sum(xi) / n + cvx.sum(A[Z, :] * w) / n + cs * w
          )
          # Constraints
          constraints = [xi + A[P, :] * w >= 1]
  
          # Solve problem
          prob = cvx.Problem(obj, constraints)
          prob.solve(solver=self.solver, verbose=self.verbose)
  
          # Extract dual variables
          r[P] = -constraints[0].dual_value
  
          # Beam search for conjunctions with negative reduced cost
          # Most negative reduced cost among current variables
          UB = np.dot(r, A) + cs
          UB = min(UB.min(), 0)
          v, zNew, Anew = beam_search(
              r,
              X,
              self.lambda0,
              self.lambda1,
              K=self.K,
              UB=UB,
              D=self.D,
              B=self.B,
              eps=self.eps,
          )
  
      # Save generated conjunctions and LP solution
      self.z = z
      self.wLP = w.value
  
      r = np.full(nP, 1.0 / n)
      self.w = beam_search_K1(
          r,
          pd.DataFrame(1 - A[P, :]),
          0,
          A[Z, :].sum(axis=0) / n + cs,
          UB=r.sum(),
          D=100,
          B=2 * self.B,
          eps=self.eps,
          stopEarly=False,
      )[1].values.ravel()
      if len(self.w) == 0:
          self.w = np.zeros_like(self.wLP, dtype=int)
  
file_path: AIX360/aix360/algorithms/rbm/boolean_rule_cg.py
imports: import os
  import numpy
  import pandas
  import cvxpy
  from sklearn.metrics import confusion_matrix, accuracy_score
  from sklearn.base import BaseEstimator, ClassifierMixin
  import time
  from .beam_search import beam_search, beam_search_K1
label_desc: Use image node_id 2 for calling the BooleanRuleCG obj's underlying member method code with example usage: obj.fit(X, y) without return types