Source code for routee.powertrain.estimators.ngboost_estimator

from __future__ import annotations

import io
import pandas as pd

from importlib.util import find_spec

from routee.powertrain.core.model_config import ModelConfig, PredictMethod
from routee.powertrain.estimators.estimator_interface import (
    ColumnSpec,
    Estimator,
)
from typing import List


[docs] class NGBoostEstimator(Estimator): file_extension: str = ".joblib" def __init__(self, ngboost) -> None: self.model = ngboost
[docs] def output_column_specs(self, config: ModelConfig) -> List[ColumnSpec]: """NGBoost emits a point prediction plus a per-target standard deviation.""" target = config.target.targets[0] return [ ColumnSpec.from_data_column(target), ColumnSpec( name=f"{target.name}_std", units=target.units, dtype=target.dtype ), ]
[docs] def to_bytes(self) -> bytes: try: import joblib except ImportError: raise ImportError( "The NGBoostEstimator estimator requires extra dependencies like joblib and ngboost. " "To install, you can do pip install routee.powertrain[ngboost]" ) byte_stream = io.BytesIO() joblib.dump(self.model, byte_stream) byte_stream.seek(0) return byte_stream.read()
[docs] @classmethod def from_bytes(cls, data: bytes) -> NGBoostEstimator: if find_spec("joblib") is None: raise ImportError( "The NGBoostEstimator estimator requires extra dependencies like joblib and ngboost. " "To install, you can do pip install routee.powertrain[ngboost]" ) import joblib byte_stream = io.BytesIO(data) ngboost_model = joblib.load(byte_stream) return cls(ngboost_model)
[docs] def predict( self, links_df: pd.DataFrame, config: ModelConfig, ) -> pd.DataFrame: distance = config.distance target_set = config.target predict_method = config.predict_method if len(target_set.targets) != 1: raise ValueError( "NGBoost only supports a single energy target. " "Please use a different estimator for multiple energy targets." ) energy = target_set.targets[0] distance_col = distance.name if predict_method not in (PredictMethod.RATE, PredictMethod.RAW): raise ValueError( f"Predict method {predict_method} is not supported by NGBoostEstimator" ) # Single source of truth for the positional input order (features, plus # distance appended for RAW) — matches the embedded input contract. x = links_df[config.all_feature_names].values energy_pred_series = self.model.pred_dist(x.tolist()) energy_pred_mean = energy_pred_series.loc energy_pred_std = energy_pred_series.scale energy_df = pd.DataFrame(index=links_df.index) if predict_method == PredictMethod.RAW: energy_pred_mean = energy_pred_mean energy_pred_std = energy_pred_std elif predict_method == PredictMethod.RATE: energy_pred_mean = energy_pred_mean * links_df[distance_col] energy_pred_std = energy_pred_std * links_df[distance_col] else: raise ValueError( f"Predict method {predict_method} is not supported by NGBoostEstimator" ) energy_df[energy.name] = energy_pred_mean energy_df[energy.name + "_std"] = energy_pred_std return energy_df