class_docstr: FIGSExt (sum of trees) classifier.
  Fast Interpretable Greedy-Tree Sums (FIGS) is an algorithm for fitting concise rule-based models.
  Specifically, FIGS generalizes CART to simultaneously grow a flexible number of trees in a summation.
  The total number of splits across all the trees can be restricted by a pre-specified threshold, keeping the model interpretable.
  Experiments across a wide array of real-world datasets show that FIGS achieves state-of-the-art prediction performance when restricted to just a few splits (e.g. less than 20).
  https://arxiv.org/abs/2201.11931
docstr: This can be made a lot faster
  Assumes there are at least 5 points in node
  Doesn't currently support _sample_weight!
code: def _construct_node_linear(
      self, X, y, idxs, tree_num=0, sample_weight=None
  ):
      """This can be made a lot faster
      Assumes there are at least 5 points in node
      Doesn't currently support _sample_weight!
      """
      y_target = y[idxs]
      impurity_orig = np.mean(np.square(y_target)) * idxs.sum()
  
      # find best linear split
      best_impurity = impurity_orig
      best_linear_coef = None
      best_feature = None
      for feature_num in range(X.shape[1]):
          x = X[idxs, feature_num].reshape(-1, 1)
          m = RidgeCV(fit_intercept=False)
          m.fit(x, y_target)
          impurity = np.min(-m.best_score_) * idxs.sum()
          assert impurity >= 0, "impurity should not be negative"
          if impurity < best_impurity:
              best_impurity = impurity
              best_linear_coef = m.coef_[0]
              best_feature = feature_num
      impurity_reduction = impurity_orig - best_impurity
  
      # no good linear fit found
      if impurity_reduction == 0:
          return Node(
              idxs=idxs,
              value=np.mean(y_target),
              tree_num=tree_num,
              feature=None,
              threshold=None,
              impurity_reduction=-1,
              split_or_linear="split",
          )  # leaf node that just returns its value
      else:
          assert isinstance(
              best_linear_coef, float
          ), "coef should be a float"
          return Node(
              idxs=idxs,
              value=best_linear_coef,
              tree_num=tree_num,
              feature=best_feature,
              threshold=None,
              impurity_reduction=impurity_reduction,
              split_or_linear="linear",
          )
  
imports: from copy import deepcopy
  import numpy
  from matplotlib import pyplot
  from sklearn import datasets
  from sklearn import tree
  from sklearn.base import BaseEstimator
  from sklearn.linear_model import RidgeCV, RidgeClassifierCV
  from sklearn.model_selection import train_test_split
  from sklearn.tree import plot_tree
  from sklearn.utils import check_X_y
  from imodels.tree.viz_utils import extract_sklearn_tree_from_figs
label_desc: Use image node_id 4 for calling the FIGSExt obj's underlying member method code with example usage: obj._construct_node_linear(X, y, idxs, tree_num, sample_weight) and returns: Node, Node