class_docstr: Random Tree generator.
  
  This generator is based on [^1]. The generator creates a random
  tree by splitting features at random and setting labels at its leaves.
  
  The tree structure is composed of node objects, which can be either inner
  nodes or leaf nodes. The choice comes as a function of the parameters
  passed to its initializer.
  
  Since the concepts are generated and classified according to a tree
  structure, in theory, it should favor decision tree learners.
  
  Parameters
  ----------
  seed_tree
      Seed for random generation of tree.
  seed_sample
      Seed for random generation of instances.
  n_classes
      The number of classes to generate.
  n_num_features
      The number of numerical features to generate.
  n_cat_features
      The number of categorical features to generate.
  n_categories_per_feature
      The number of values to generate per categorical feature.
  max_tree_depth
      The maximum depth of the tree concept.
  first_leaf_level
      The first level of the tree above `max_tree_depth` that can have leaves.
  fraction_leaves_per_level
      The fraction of leaves per level from `first_leaf_level` onwards.
  
  Examples
  --------
  
  >>> from river.datasets import synth
  
  >>> dataset = synth.RandomTree(seed_tree=42, seed_sample=42, n_classes=2,
  ...                            n_num_features=2, n_cat_features=2,
  ...                            n_categories_per_feature=2, max_tree_depth=6,
  ...                            first_leaf_level=3, fraction_leaves_per_level=0.15)
  
  >>> for x, y in dataset.take(5):
  ...     print(x, y)
  {'x_num_0': 0.6394, 'x_num_1': 0.0250, 'x_cat_0': 1, 'x_cat_1': 0} 0
  {'x_num_0': 0.2232, 'x_num_1': 0.7364, 'x_cat_0': 0, 'x_cat_1': 1} 1
  {'x_num_0': 0.0317, 'x_num_1': 0.0936, 'x_cat_0': 0, 'x_cat_1': 0} 0
  {'x_num_0': 0.5612, 'x_num_1': 0.7160, 'x_cat_0': 1, 'x_cat_1': 0} 0
  {'x_num_0': 0.4492, 'x_num_1': 0.2781, 'x_cat_0': 0, 'x_cat_1': 0} 0
  
  References
  ----------
  [^1]: Domingos, Pedro, and Geoff Hulten. "Mining high-speed data streams."
        In Proceedings of the sixth ACM SIGKDD international conference on
        Knowledge discovery and data mining, pp. 71-80. 2000.
class_docstr_tok: ["Random","Tree","generator",".","This","generator","is","based","on","[","^1","]",".","The","generator","creates","a","random","tree","by","splitting","features","at","random","and","setting","labels","at","its","leaves",".","The","tree","structure","is","composed","of","node","objects",",","which","can","be","either","inner","nodes","or","leaf","nodes",".","The","choice","comes","as","a","function","of","the","parameters","passed","to","its","initializer",".","Since","the","concepts","are","generated","and","classified","according","to","a","tree","structure",",","in","theory",",","it","should","favor","decision","tree","learners",".","Parameters","--","--","--","--","--","seed_tree","Seed","for","random","generation","of","tree",".","seed_sample","Seed","for","random","generation","of","instances",".","n_classes","The","number","of","classes","to","generate",".","n_num_features","The","number","of","numerical","features","to","generate",".","n_cat_features","The","number","of","categorical","features","to","generate",".","n_categories_per_feature","The","number","of","values","to","generate","per","categorical","feature",".","max_tree_depth","The","maximum","depth","of","the","tree","concept",".","first_leaf_level","The","first","level","of","the","tree","above","`","max_tree_depth","`","that","can","have","leaves",".","fraction_leaves_per_level","The","fraction","of","leaves","per","level","from","`","first_leaf_level","`","onwards",".","Examples","--","--","--","--",">",">",">","from","river.datasets","import","synth",">",">",">","dataset","=","synth.RandomTree","(","seed_tree=42",",","seed_sample=42",",","n_classes=2",",","...","n_num_features=2",",","n_cat_features=2",",","...","n_categories_per_feature=2",",","max_tree_depth=6",",","...","first_leaf_level=3",",","fraction_leaves_per_level=0.15",")",">",">",">","for","x",",","y","in","dataset.take","(","5",")",":","...","print","(","x",",","y",")","{","'x_num_0","'",":","0.6394",",","'x_num_1","'",":","0.0250",",","'x_cat_0","'",":","1",",","'x_cat_1","'",":","0","}","0","{","'x_num_0","'",":","0.2232",",","'x_num_1","'",":","0.7364",",","'x_cat_0","'",":","0",",","'x_cat_1","'",":","1","}","1","{","'x_num_0","'",":","0.0317",",","'x_num_1","'",":","0.0936",",","'x_cat_0","'",":","0",",","'x_cat_1","'",":","0","}","0","{","'x_num_0","'",":","0.5612",",","'x_num_1","'",":","0.7160",",","'x_cat_0","'",":","1",",","'x_cat_1","'",":","0","}","0","{","'x_num_0","'",":","0.4492",",","'x_num_1","'",":","0.2781",",","'x_cat_0","'",":","0",",","'x_cat_1","'",":","0","}","0","References","--","--","--","--","--","[","^1","]",":","Domingos",",","Pedro",",","and","Geoff","Hulten",".","``","Mining","high-speed","data","streams",".","''","In","Proceedings","of","the","sixth","ACM","SIGKDD","international","conference","on","Knowledge","discovery","and","data","mining",",","pp",".","71-80",".","2000","."]
docstr: Creates a node, choosing at random the splitting feature and value.
  Then recursively generates its children. If the split feature is a
  numerical feature there will be two children nodes (left and right),
  one for samples where the value for the split feature is smaller than
  the split value, and one for the other case. For categorical features,
  the number of children generated is equal to the number of categories
  per categorical feature.
  
  Once the recursion passes the leaf_node minimum depth, it probabilistic
  chooses if the node is a leaf_node or not. If not, the recursion follow
  the same way as before. If it decides the node is a leaf_node, a class
  label is chosen for the leaf_node at random.
  
  Finally, if the current_depth is equal or higher than the tree
  maximum depth, a leaf_node node is immediately returned.
  
  Parameters
  ----------
  current_depth
      The current tree depth.
  candidate_features
      Candidate features
  min_numeric_value
      The minimum numeric feature value, on this branch of the tree.
  max_numeric_value
      The minimum numeric feature value, on this branch of the tree.
  rng
      A random number generator instance.
  
  Notes
  -----
  If the splitting attribute of a node happens to be a nominal attribute
  we guarantee that none of its children will split on the same attribute,
  as it would have no use for that split.
docstr_tok: ["Creates","a","node",",","choosing","at","random","the","splitting","feature","and","value",".","Then","recursively","generates","its","children",".","If","the","split","feature","is","a","numerical","feature","there","will","be","two","children","nodes","(","left","and","right",")",",","one","for","samples","where","the","value","for","the","split","feature","is","smaller","than","the","split","value",",","and","one","for","the","other","case",".","For","categorical","features",",","the","number","of","children","generated","is","equal","to","the","number","of","categories","per","categorical","feature",".","Once","the","recursion","passes","the","leaf_node","minimum","depth",",","it","probabilistic","chooses","if","the","node","is","a","leaf_node","or","not",".","If","not",",","the","recursion","follow","the","same","way","as","before",".","If","it","decides","the","node","is","a","leaf_node",",","a","class","label","is","chosen","for","the","leaf_node","at","random",".","Finally",",","if","the","current_depth","is","equal","or","higher","than","the","tree","maximum","depth",",","a","leaf_node","node","is","immediately","returned",".","Parameters","--","--","--","--","--","current_depth","The","current","tree","depth",".","candidate_features","Candidate","features","min_numeric_value","The","minimum","numeric","feature","value",",","on","this","branch","of","the","tree",".","max_numeric_value","The","minimum","numeric","feature","value",",","on","this","branch","of","the","tree",".","rng","A","random","number","generator","instance",".","Notes","--","--","-","If","the","splitting","attribute","of","a","node","happens","to","be","a","nominal","attribute","we","guarantee","that","none","of","its","children","will","split","on","the","same","attribute",",","as","it","would","have","no","use","for","that","split","."]
code: def _generate_random_tree_node(
      self,
      current_depth: int,
      candidate_features: list,
      min_numeric_value: list,
      max_numeric_value: list,
      rng: random.Random,
  ):
      """
      Creates a node, choosing at random the splitting feature and value.
      Then recursively generates its children. If the split feature is a
      numerical feature there will be two children nodes (left and right),
      one for samples where the value for the split feature is smaller than
      the split value, and one for the other case. For categorical features,
      the number of children generated is equal to the number of categories
      per categorical feature.
  
      Once the recursion passes the leaf_node minimum depth, it probabilistic
      chooses if the node is a leaf_node or not. If not, the recursion follow
      the same way as before. If it decides the node is a leaf_node, a class
      label is chosen for the leaf_node at random.
  
      Finally, if the current_depth is equal or higher than the tree
      maximum depth, a leaf_node node is immediately returned.
  
      Parameters
      ----------
      current_depth
          The current tree depth.
      candidate_features
          Candidate features
      min_numeric_value
          The minimum numeric feature value, on this branch of the tree.
      max_numeric_value
          The minimum numeric feature value, on this branch of the tree.
      rng
          A random number generator instance.
  
      Notes
      -----
      If the splitting attribute of a node happens to be a nominal attribute
      we guarantee that none of its children will split on the same attribute,
      as it would have no use for that split.
  
      """
      # Stop recursive call
      if (current_depth >= self.max_tree_depth) or (
          (current_depth >= self.first_leaf_level)
          and (self.fraction_leaves_per_level >= (1.0 - rng.random()))
      ):
          leaf_node = TreeNode()
          leaf_node.class_label = rng.randint(0, self.n_classes - 1)
          return leaf_node
      # Create a new node
      split_node = TreeNode()
      chosen_feature = rng.randint(0, len(candidate_features) - 1)
      if chosen_feature < self.n_num_features:
          # Chosen feature is numeric
          split_node.split_feature_idx = chosen_feature
          min_val = min_numeric_value[chosen_feature]
          max_val = max_numeric_value[chosen_feature]
          split_node.split_feature_val = (
              max_val - min_val
          ) * rng.random() + min_val
          # Left node
          new_max_value = list(max_numeric_value)
          new_max_value[chosen_feature] = split_node.split_feature_val
          split_node.children.append(
              self._generate_random_tree_node(
                  current_depth + 1,
                  candidate_features,
                  min_numeric_value,
                  new_max_value,
                  rng,
              )
          )
          # Right node
          new_min_value = list(min_numeric_value)
          new_min_value[chosen_feature] = split_node.split_feature_val
          split_node.children.append(
              self._generate_random_tree_node(
                  current_depth + 1,
                  candidate_features,
                  new_min_value,
                  max_numeric_value,
                  rng,
              )
          )
      else:
          # Chosen feature is categorical
          split_node.split_feature_idx = candidate_features[
              chosen_feature
          ]
          # Remove chosen features from candidates
          new_candidates = [
              c
              for c in candidate_features
              if c != split_node.split_feature_idx
          ]
          # Generate children per category
          for i in range(self.n_categories_per_feature):
              split_node.children.append(
                  self._generate_random_tree_node(
                      current_depth + 1,
                      new_candidates,
                      min_numeric_value,
                      max_numeric_value,
                      rng,
                  )
              )
      return split_node
  
file_path: river/river/datasets/synth/random_tree.py
imports: from __future__ import annotations
  import random
  from river import datasets
label_desc: Use image node_id 3 for calling the RandomTree obj's underlying member method code with example usage: obj._generate_random_tree_node(current_depth, candidate_features, min_numeric_value, max_numeric_value, rng) and returns: split_node, leaf_node