class_docstr: Random Forest classifier. Uses a collection of classification trees that
  trains on random subsets of the data using a random subsets of the features.
  
  Parameters:
  -----------
  n_estimators: int
      The number of classification trees that are used.
  max_features: int
      The maximum number of features that the classification trees are allowed to
      use.
  min_samples_split: int
      The minimum number of samples needed to make a split when building a tree.
  min_gain: float
      The minimum impurity required to split the tree further. 
  max_depth: int
      The maximum depth of a tree.
code: def predict(self, X):
      y_preds = np.empty((X.shape[0], len(self.trees)))
      # Let each tree make a prediction on the data
      for i, tree in enumerate(self.trees):
          # Indices of the features that the tree has trained on
          idx = tree.feature_indices
          # Make a prediction based on those features
          prediction = tree.predict(X[:, idx])
          y_preds[:, i] = prediction
  
      y_pred = []
      # For each sample
      for sample_predictions in y_preds:
          # Select the most common class prediction
          y_pred.append(
              np.bincount(sample_predictions.astype("int")).argmax()
          )
      return y_pred
  
file_path: ML-From-Scratch/mlfromscratch/supervised_learning/random_forest.py
imports: from __future__ import division, print_function
  import numpy
  import math
  import progressbar
  from mlfromscratch.utils import divide_on_feature, train_test_split, get_random_subsets, normalize
  from mlfromscratch.utils import accuracy_score, calculate_entropy
  from mlfromscratch.unsupervised_learning import PCA
  from mlfromscratch.supervised_learning import ClassificationTree
  from mlfromscratch.utils.misc import bar_widgets
  from mlfromscratch.utils import Plot
label_desc: Use image node_id 3 for calling the RandomForest obj's underlying member method code with example usage: obj.predict(X) and returns: y_pred