Source code for routee.powertrain.trainers.sklearn_random_forest

from enum import Enum

import numpy as np
import pandas as pd
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
from sklearn.ensemble import RandomForestRegressor

from routee.powertrain.core.model_config import ModelConfig
from routee.powertrain.estimators.estimator_interface import Estimator
from routee.powertrain.estimators.onnx import ONNX_INPUT_NAME, ONNXEstimator
from routee.powertrain.trainers.trainer import Trainer


[docs] class RandomForestTrainerOutput(Enum): ONNX = 1
[docs] class SklearnRandomForestTrainer(Trainer): architecture_tag: str = "random_forest" def __init__( self, max_depth: int = 10, min_samples_split: int = 10, n_estimators: int = 20, random_state: int = 52, cores: int = 4, output_type=RandomForestTrainerOutput.ONNX, ): self.max_depth = max_depth self.min_samples_split = min_samples_split self.n_estimators = n_estimators self.random_state = random_state self.cores = cores self.output_type = output_type
[docs] def inner_train( self, features: pd.DataFrame, target: pd.DataFrame, config: ModelConfig, validation_features: pd.DataFrame | None = None, validation_target: pd.DataFrame | None = None, ) -> Estimator: """ Uses a random forest to predict the energy rate values """ rf = RandomForestRegressor( n_estimators=self.n_estimators, max_depth=self.max_depth, min_samples_split=self.min_samples_split, n_jobs=self.cores, random_state=self.random_state, ) X = features.values y: np.ndarray = target.values if y.shape[1] == 1: y = y.ravel() rf.fit(X, y) if self.output_type == RandomForestTrainerOutput.ONNX: # convert to ONNX n_features = len(features.columns) n_targets = len(target.columns) # explicity specify the output shape since skl2onnx was not able to infer it def custom_transform_shape_calculator(operator): operator.outputs[0].type = FloatTensorType([None, n_targets]) initial_type = [(ONNX_INPUT_NAME, FloatTensorType([None, n_features]))] onnx_model = convert_sklearn( rf, initial_types=initial_type, custom_shape_calculators={ rf.__class__: custom_transform_shape_calculator }, ) estimator = ONNXEstimator(onnx_model) else: # extension point here for adding other estimator output types raise ValueError(f"Unknown output type: {self.output_type}") return estimator