Source code for alf_core.dataclasses.results

# Copyright 2026 InstaDeep Ltd. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from dataclasses import dataclass
from typing import Union

import numpy as np

from alf_core.dataclasses.predictions import Predictions
from alf_core.utils.enums import ProblemType
from alf_core.utils.metrics import classification_metric_registry, regression_metric_registry


[docs] @dataclass class Results: """Computes metrics based on the predictions and targets. Attributes: targets: A numpy array of ground truth target values. predictions: A Predictions object containing model predictions. problem_type: Type of problem determining which metrics are computed. """ targets: np.ndarray predictions: Predictions problem_type: ProblemType def __post_init__(self) -> None: """Validate inputs and compute metrics. Raises: AssertionError: If targets and predictions have different lengths. """ assert self.targets.shape[0] == self.predictions.means.shape[0], ( f"Targets and predictions must have the same length (number of samples), " f"got targets.shape={self.targets.shape} and " f"predictions.means.shape={self.predictions.means.shape}" ) self.metrics = self.compute_metrics()
[docs] def compute_metrics(self) -> dict[str, Union[float, int, np.number]]: """Compute evaluation metrics based on predictions and targets. For regression, routes to the variance-aware regression registry. For classification (binary or multiclass), routes to the classification metric registry using the probability array stored in `predictions.means`. Raises: ValueError: If the problem type is unrecognized. Returns: A dictionary of metric names to their computed values. """ metrics: dict[str, Union[float, int, np.number]] = {} if self.problem_type == ProblemType.REGRESSION: # Always compute the variance-independent metrics, if the surrogate # provides variances, compute the variance-dependent metrics as well. metrics_dict = dict(regression_metric_registry.get_metrics(requires_variance=False)) if self.predictions.variances is not None: metrics_dict.update(regression_metric_registry.get_metrics(requires_variance=True)) for _, metric_fn in metrics_dict.items(): metric_update = metric_fn( self.predictions.means, self.predictions.variances, self.targets ) metrics.update(metric_update) elif self.problem_type in (ProblemType.BINARY, ProblemType.MULTICLASS): for _, metric_fn in classification_metric_registry.get_metrics().items(): metrics.update(metric_fn(self.predictions.means, self.targets)) else: raise ValueError(f"Unhandled ProblemType in compute_metrics: {self.problem_type!r}") return metrics