docstr: Fits the RandomForest model.
  
  :param train_data: encoded features for training dataset
  :param dev_data: encoded features for dev dataset
docstr_tok: ["Fits","the","RandomForest","model",".",":","param","train_data",":","encoded","features","for","training","dataset",":","param","dev_data",":","encoded","features","for","dev","dataset"]
code: def fit(self, train_data: EncodedDs, dev_data: EncodedDs) -> None:
      """
      Fits the RandomForest model.
  
      :param train_data: encoded features for training dataset
      :param dev_data: encoded features for dev dataset
      """
      started = time.time()
      log.info("Started fitting RandomForest model")
  
      output_dtype = self.dtype_dict[self.target]
  
      if output_dtype not in self.cls_dtypes + self.num_dtypes:
          log.error(
              f"RandomForest mixer not supported for type: {output_dtype}"
          )
          raise Exception(
              f"RandomForest mixer not supported for type: {output_dtype}"
          )
  
      # concat the data if fit on dev
      if self.fit_on_dev:
          train_data = ConcatedEncodedDs([train_data, dev_data])
  
      # initialize the model
      init_params = {
          "n_estimators": 50,
          "max_depth": 5,
          "bootstrap": True,
          "n_jobs": -1,
          "random_state": 0,
      }
  
      if self.is_classifier:
          X = train_data.get_encoded_data(include_target=False)
          Y = train_data.get_column_original_data(self.target)
  
          self.model = RandomForestClassifier(**init_params)
  
          self.model.fit(X, Y)  # sample_weight
  
          self.map = {
              cat: idx for idx, cat in enumerate(self.model.classes_)
          }  # for multi_logloss
      else:
          X = train_data.get_encoded_data(include_target=False)
          Y = train_data.get_encoded_column_data(self.target)
  
          self.model = RandomForestRegressor(**init_params)
  
          self.model.fit(X, Y)  # sample_weight
  
      # optimize params
      metric, predict_method = (
          (self._multi_logloss, "predict_proba")
          if self.is_classifier
          else (mean_squared_error, "predict")
      )
  
      def objective(trial: trial_module.Trial):
          criterion = (
              trial.suggest_categorical("criterion", "gini")
              if self.is_classifier
              else "squared_error"
          )
  
          params = {
              "n_estimators": trial.suggest_int("n_estimators", 2, 512),
              "criterion": criterion,
          }
  
          self.model.set_params(**params)
  
          y_pred = cross_val_predict(
              self.model, X, Y, cv=self.cv, method=predict_method
          )
          cv = check_cv(self.cv, Y, classifier=self.is_classifier)  #
          score = np.mean(
              [
                  metric(np.array(Y)[val_idx], y_pred[val_idx])
                  for _, val_idx in cv.split(X, Y)
              ]
          )
  
          return score
  
      elapsed = time.time() - started
      num_trials = max(
          min(int(self.stop_after / elapsed) - 2, self.num_trials), 0
      )
      if self.use_optuna:
          log.info(f"The number of trials (Optuna) is {num_trials}.")
  
      if self.use_optuna and num_trials > 0:
          init_score = metric(Y, getattr(self.model, predict_method)(X))
  
          study = optuna.create_study(direction="minimize")
          study.optimize(objective, n_trials=num_trials)
  
          opt_model = clone(self.model)
          opt_model.set_params(**study.best_params)
          opt_model.fit(X, Y)
          optuna_score = metric(
              Y, getattr(opt_model, predict_method)(X)
          )
          log.info(
              f"init_score: {init_score}, optuna_score: {optuna_score}"
          )
  
          if init_score <= optuna_score:
              self.model.set_params(**init_params)
          else:
              self.model = opt_model
              log.info(
                  f"RandomForest parameters of the best trial: {study.best_params}"
              )
  
      # evaluate model effects
      if self.fit_on_dev:
          log.info(
              f"RandomForest based correlation of (train data): {self.model.score(X, Y)}"
          )
          X = dev_data.get_encoded_data(include_target=False)
          if self.is_classifier:
              Y = dev_data.get_column_original_data(self.target)
          else:
              Y = dev_data.get_encoded_column_data(self.target)
          log.info(
              f"RandomForest based correlation of (dev data): {self.model.score(X, Y)}"
          )
      else:
          log.info(
              f"RandomForest based correlation of: {self.model.score(X, Y)}"
          )
  
imports: import time
  import math
  import torch
  import numpy
  import pandas
  import optuna
  from typing import Dict, Union, Optional
  from optuna import trial
  from sklearn import clone
  from sklearn.metrics import mean_squared_error
  from sklearn.model_selection import check_cv, cross_val_predict
  from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
  from type_infer.dtype import dtype
  from lightwood.helpers.log import log
  from lightwood.encoder.base import BaseEncoder
  from lightwood.data.encoded_ds import EncodedDs, ConcatedEncodedDs
  from lightwood.mixer.base import BaseMixer
  from lightwood.api.types import PredictionArguments
label_desc: Use image node_id 3 for calling the RandomForest obj's underlying member method code with example usage: obj.fit(train_data, dev_data) and returns: score