class_docstr: A C4.5 tree classifier.
  
  Parameters
  ----------
  max_rules : int, optional (default=None)
      Maximum number of split nodes allowed in the tree
class_docstr_tok: ["A","C4.5","tree","classifier",".","Parameters","--","--","--","--","--","max_rules",":","int",",","optional","(","default=None",")","Maximum","number","of","split","nodes","allowed","in","the","tree"]
docstr: Parameters
  ----------
  X_t: List[list]
      input data transposed (num_features x num_observations)
  y_str: List[str]
      outcome represented as strings
  
  parent
  attrs_names
docstr_tok: ["Parameters","--","--","--","--","--","X_t",":","List","[","list","]","input","data","transposed","(","num_features","x","num_observations",")","y_str",":","List","[","str","]","outcome","represented","as","strings","parent","attrs_names"]
code: def grow_tree(
      self, X_t: List[list], y_str: List[str], parent, attrs_names
  ):
      """
      Parameters
      ----------
      X_t: List[list]
          input data transposed (num_features x num_observations)
      y_str: List[str]
          outcome represented as strings
  
      parent
      attrs_names
  
      """
      # check that y contains more than 1 distinct value
      if len(set(y_str)) > 1:
          split = []
  
          # loop over features and build up potential splits
          for i in range(len(X_t)):
              if set(X_t[i]) == set("?"):
                  split.append(0)
              else:
                  if is_numeric_feature(X_t[i]):
                      split.append(gain(y_str, X_t[i]))
                  else:
                      split.append(gain_ratio(y_str, X_t[i]))
  
          # no good split, return child node
          if max(split) == 0:
              set_as_leaf_node(parent, y_str)
  
          # there is a good split
          else:
              index_selected = split.index(max(split))
              name_selected = str(attrs_names[index_selected])
              self.complexity_ += 1
              if is_numeric_feature(X_t[index_selected]):
                  # split on this point
                  split_point = get_best_split(
                      y_str, X_t[index_selected]
                  )
  
                  # build up children nodes
                  r_child_X = [[] for i in range(len(X_t))]
                  r_child_y = []
                  l_child_X = [[] for i in range(len(X_t))]
                  l_child_y = []
                  for i in range(len(y_str)):
                      if not X_t[index_selected][i] == "?":
                          if float(X_t[index_selected][i]) < float(
                              split_point
                          ):
                              l_child_y.append(y_str[i])
                              for j in range(len(X_t)):
                                  l_child_X[j].append(X_t[j][i])
                          else:
                              r_child_y.append(y_str[i])
                              for j in range(len(X_t)):
                                  r_child_X[j].append(X_t[j][i])
  
                  # grow child nodes as well
                  if (
                      len(l_child_y) > 0
                      and len(r_child_y) > 0
                      and (
                          self.max_rules is None
                          or self.complexity_ <= self.max_rules
                      )
                  ):
                      p_l = float(len(l_child_y)) / (
                          len(X_t[index_selected])
                          - X_t[index_selected].count("?")
                      )
                      son = ET.SubElement(
                          parent,
                          name_selected,
                          {
                              "feature": str(split_point),
                              "flag": "l",
                              "p": str(round(p_l, 3)),
                          },
                      )
                      self.grow_tree(
                          l_child_X, l_child_y, son, attrs_names
                      )
                      son = ET.SubElement(
                          parent,
                          name_selected,
                          {
                              "feature": str(split_point),
                              "flag": "r",
                              "p": str(round(1 - p_l, 3)),
                          },
                      )
                      self.grow_tree(
                          r_child_X, r_child_y, son, attrs_names
                      )
                  else:
                      num_max = 0
                      for cat in set(y_str):
                          num_cat = y_str.count(cat)
                          if num_cat > num_max:
                              num_max = num_cat
                              most_cat = cat
                      parent.text = most_cat
              else:
                  # split on non-numeric variable (e.g. categorical)
                  # create a leaf for each unique value
                  for k in set(X_t[index_selected]):
                      if not k == "?" and (
                          self.max_rules is None
                          or self.complexity_ <= self.max_rules
                      ):
                          child_X = [[] for i in range(len(X_t))]
                          child_y = []
                          for i in range(len(y_str)):
                              if X_t[index_selected][i] == k:
                                  child_y.append(y_str[i])
                                  for j in range(len(X_t)):
                                      child_X[j].append(X_t[j][i])
                          son = ET.SubElement(
                              parent,
                              name_selected,
                              {
                                  "feature": k,
                                  "flag": "m",
                                  "p": str(
                                      round(
                                          float(len(child_y))
                                          / (
                                              len(X_t[index_selected])
                                              - X_t[
                                                  index_selected
                                              ].count("?")
                                          ),
                                          3,
                                      )
                                  ),
                              },
                          )
                          self.grow_tree(
                              child_X, child_y, son, attrs_names
                          )
      else:
          parent.text = y_str[0]
  
imports: import copy
  from copy import deepcopy
  from typing import List
  from xml.dom import minidom
  from xml.etree import ElementTree
  import numpy
  import pandas
  from sklearn.base import BaseEstimator, ClassifierMixin
  from sklearn.model_selection import cross_val_score
  from sklearn.utils.validation import check_array, check_is_fitted, check_X_y
  from imodels.util.arguments import check_fit_arguments
  from ..c45_tree.c45_utils import decision, is_numeric_feature, gain, gain_ratio, get_best_split, set_as_leaf_node
  from ...util.data_util import get_clean_dataset
label_desc: Use image node_id 9 for calling the C45TreeClassifier obj's underlying member method code with example usage: obj.grow_tree(X_t, y_str, parent, attrs_names) without return types