Skip to content

RegressionCV

Auto-tuned regression with Bayesian optimization. For practical examples, see the API Guide.

regression_cv

Definition for RegressionCV.

RegressionCV

Bases: BaseAutoCV, RegressorMixin, ExplainerMixIn

Defines an auto regression tree, based on the bayesian optimization base class.

Source code in src/tree_machine/regression_cv.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
class RegressionCV(BaseAutoCV, RegressorMixin, ExplainerMixIn):
    """
    Defines an auto regression tree, based on the bayesian optimization base class.
    """

    model_: XGBRegressor | CatBoostRegressor
    feature_importances_: NDArray[np.float64]
    explainer_: TreeExplainer

    @validate_call(config={"arbitrary_types_allowed": True})
    def __init__(
        self,
        metric: AcceptableRegression,
        cv: BaseCrossValidator,
        n_trials: NonNegativeInt,
        timeout: NonNegativeInt,
        config: RegressionCVConfig,
        backend: str = "xgboost",
    ) -> None:
        """
        Constructor for RegressionCV.

        Args:
            metric: Loss metric to use as base for the estimation process.
            cv: Splitter object to use when estimating the model.
            n_trials: Number of optimization trials to use when finding a model.
            timeout: Timeout in seconds to stop the optimization.
            config: Configuration to use when fitting the model.
            backend: Backend to use for the model. Either "xgboost" or "catboost".
        """
        super().__init__(metric, cv, n_trials, timeout)
        self.config = config
        self.backend = backend

    def explain(self, X: Inputs, **explainer_params) -> dict[str, NDArray[np.float64]]:
        """
        Explains the inputs.
        """

        check_is_fitted(self, "model_", msg="Model is not fitted.")

        if getattr(self, "explainer_", None) is None:
            self.explainer_ = TreeExplainer(self.model_, **explainer_params)

        return {
            "mean_value": self.explainer_.expected_value,
            "shap_values": self.explainer_.shap_values(self._validate_X(X)),
        }

    def fit(self, X: Inputs, y: GroundTruth, **fit_params) -> "RegressionCV":
        """
        Fits RegressionCV.

        Args:
            X: input data to use in fitting trees.
            y: actual targets for fitting.
        """
        self.feature_names_ = list(X.columns) if isinstance(X, pd.DataFrame) else []

        constraints = self.config.get_kwargs(self.feature_names_, backend=self.backend)

        if self.backend == "xgboost":
            estimator_type = partial(XGBRegressor, enable_categorical=True)
        elif self.backend == "catboost":
            estimator_type = partial(
                CatBoostRegressor, verbose=False, allow_writing_files=False
            )
        else:
            raise ValueError(
                f"Unknown backend: {self.backend}. Must be 'xgboost' or 'catboost'."
            )

        self.model_ = self.optimize(
            estimator_type=estimator_type,
            X=self._validate_X(X),
            y=self._validate_y(y),
            parameters=self.config.parameters,
            return_train_score=self.config.return_train_score,
            backend=self.backend,
            X_validation=fit_params.get("X_validation", pd.DataFrame()),
            y_validation=fit_params.get("y_validation", pd.Series()),
            **constraints,
        )
        self.feature_importances_ = self.model_.feature_importances_

        return self

    def predict(self, X: Inputs) -> Predictions:
        """
        Returns model predictions.
        """
        check_is_fitted(self, "model_", msg="Model is not fitted.")
        return self.model_.predict(self._validate_X(X))

    @property
    def scorer(self) -> tp.Callable[..., float]:
        """
        Returns correct scorer to use when scoring with RegressionCV.
        """
        metric_func = self._resolve_metric(regression_metrics)
        return make_scorer(metric_func, greater_is_better=False)

scorer property

scorer

Returns correct scorer to use when scoring with RegressionCV.

__init__

__init__(metric, cv, n_trials, timeout, config, backend='xgboost')

Constructor for RegressionCV.

Parameters:

Name Type Description Default
metric AcceptableRegression

Loss metric to use as base for the estimation process.

required
cv BaseCrossValidator

Splitter object to use when estimating the model.

required
n_trials NonNegativeInt

Number of optimization trials to use when finding a model.

required
timeout NonNegativeInt

Timeout in seconds to stop the optimization.

required
config RegressionCVConfig

Configuration to use when fitting the model.

required
backend str

Backend to use for the model. Either "xgboost" or "catboost".

'xgboost'
Source code in src/tree_machine/regression_cv.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@validate_call(config={"arbitrary_types_allowed": True})
def __init__(
    self,
    metric: AcceptableRegression,
    cv: BaseCrossValidator,
    n_trials: NonNegativeInt,
    timeout: NonNegativeInt,
    config: RegressionCVConfig,
    backend: str = "xgboost",
) -> None:
    """
    Constructor for RegressionCV.

    Args:
        metric: Loss metric to use as base for the estimation process.
        cv: Splitter object to use when estimating the model.
        n_trials: Number of optimization trials to use when finding a model.
        timeout: Timeout in seconds to stop the optimization.
        config: Configuration to use when fitting the model.
        backend: Backend to use for the model. Either "xgboost" or "catboost".
    """
    super().__init__(metric, cv, n_trials, timeout)
    self.config = config
    self.backend = backend

explain

explain(X, **explainer_params)

Explains the inputs.

Source code in src/tree_machine/regression_cv.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def explain(self, X: Inputs, **explainer_params) -> dict[str, NDArray[np.float64]]:
    """
    Explains the inputs.
    """

    check_is_fitted(self, "model_", msg="Model is not fitted.")

    if getattr(self, "explainer_", None) is None:
        self.explainer_ = TreeExplainer(self.model_, **explainer_params)

    return {
        "mean_value": self.explainer_.expected_value,
        "shap_values": self.explainer_.shap_values(self._validate_X(X)),
    }

fit

fit(X, y, **fit_params)

Fits RegressionCV.

Parameters:

Name Type Description Default
X Inputs

input data to use in fitting trees.

required
y GroundTruth

actual targets for fitting.

required
Source code in src/tree_machine/regression_cv.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def fit(self, X: Inputs, y: GroundTruth, **fit_params) -> "RegressionCV":
    """
    Fits RegressionCV.

    Args:
        X: input data to use in fitting trees.
        y: actual targets for fitting.
    """
    self.feature_names_ = list(X.columns) if isinstance(X, pd.DataFrame) else []

    constraints = self.config.get_kwargs(self.feature_names_, backend=self.backend)

    if self.backend == "xgboost":
        estimator_type = partial(XGBRegressor, enable_categorical=True)
    elif self.backend == "catboost":
        estimator_type = partial(
            CatBoostRegressor, verbose=False, allow_writing_files=False
        )
    else:
        raise ValueError(
            f"Unknown backend: {self.backend}. Must be 'xgboost' or 'catboost'."
        )

    self.model_ = self.optimize(
        estimator_type=estimator_type,
        X=self._validate_X(X),
        y=self._validate_y(y),
        parameters=self.config.parameters,
        return_train_score=self.config.return_train_score,
        backend=self.backend,
        X_validation=fit_params.get("X_validation", pd.DataFrame()),
        y_validation=fit_params.get("y_validation", pd.Series()),
        **constraints,
    )
    self.feature_importances_ = self.model_.feature_importances_

    return self

predict

predict(X)

Returns model predictions.

Source code in src/tree_machine/regression_cv.py
190
191
192
193
194
195
def predict(self, X: Inputs) -> Predictions:
    """
    Returns model predictions.
    """
    check_is_fitted(self, "model_", msg="Model is not fitted.")
    return self.model_.predict(self._validate_X(X))

RegressionCVConfig

Available config to use when fitting a regression model.

dictionary containing monotonicity direction allowed for each

variable. 0 means no monotonicity, 1 means increasing and -1 means decreasing monotonicity.

interactions: list of lists containing permitted relationships in data. n_jobs: Number of jobs to use when fitting the model. parameters: dictionary with distribution bounds for each hyperparameter to search on during optimization. return_train_score: whether to return the train score when fitting the model. quantile_alpha: Quantile alpha to use when fitting the model, if fitting a quantile model.

Source code in src/tree_machine/regression_cv.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@dataclass(frozen=True, config={"arbitrary_types_allowed": True})
class RegressionCVConfig:
    """
    Available config to use when fitting a regression model.

    monotone_constraints: dictionary containing monotonicity direction allowed for each
        variable. 0 means no monotonicity, 1 means increasing and -1 means decreasing
        monotonicity.
    interactions: list of lists containing permitted relationships in data.
    n_jobs: Number of jobs to use when fitting the model.
    parameters: dictionary with distribution bounds for each hyperparameter to search
        on during optimization.
    return_train_score: whether to return the train score when fitting the model.
    quantile_alpha: Quantile alpha to use when fitting the model, if fitting a quantile
        model.
    """

    monotone_constraints: dict[str, int]
    interactions: list[list[str]]
    n_jobs: int
    parameters: OptimizerParams
    return_train_score: bool

    def get_kwargs(self, feature_names: list[str], backend: str = "xgboost") -> dict:
        """
        Returns parsed and validated constraint configuration for a RegressionCV model.

        Args:
            feature_names: list of feature names. If empty, will return empty
                constraints dictionaries and lists.
            backend: Backend to use for the model. Either "xgboost" or "catboost".
        """
        monotone_constraints = {
            feature_names.index(key): value
            for key, value in self.monotone_constraints.items()
        }

        if backend == "xgboost":
            return {
                "monotone_constraints": monotone_constraints,
                "interaction_constraints": [
                    [feature_names.index(key) for key in lt] for lt in self.interactions
                ],
                "n_jobs": self.n_jobs,
            }
        elif backend == "catboost":
            return {
                "monotone_constraints": monotone_constraints or None,
                "thread_count": self.n_jobs,
            }
        else:
            raise ValueError(
                f"Unknown backend: {backend}. Must be 'xgboost' or 'catboost'."
            )

get_kwargs

get_kwargs(feature_names, backend='xgboost')

Returns parsed and validated constraint configuration for a RegressionCV model.

Parameters:

Name Type Description Default
feature_names list[str]

list of feature names. If empty, will return empty constraints dictionaries and lists.

required
backend str

Backend to use for the model. Either "xgboost" or "catboost".

'xgboost'
Source code in src/tree_machine/regression_cv.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def get_kwargs(self, feature_names: list[str], backend: str = "xgboost") -> dict:
    """
    Returns parsed and validated constraint configuration for a RegressionCV model.

    Args:
        feature_names: list of feature names. If empty, will return empty
            constraints dictionaries and lists.
        backend: Backend to use for the model. Either "xgboost" or "catboost".
    """
    monotone_constraints = {
        feature_names.index(key): value
        for key, value in self.monotone_constraints.items()
    }

    if backend == "xgboost":
        return {
            "monotone_constraints": monotone_constraints,
            "interaction_constraints": [
                [feature_names.index(key) for key in lt] for lt in self.interactions
            ],
            "n_jobs": self.n_jobs,
        }
    elif backend == "catboost":
        return {
            "monotone_constraints": monotone_constraints or None,
            "thread_count": self.n_jobs,
        }
    else:
        raise ValueError(
            f"Unknown backend: {backend}. Must be 'xgboost' or 'catboost'."
        )