Skip to content
Open
15 changes: 14 additions & 1 deletion skore/src/skore/_sklearn/_estimator/metrics_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ class _MetricsAccessor(_BaseAccessor[EstimatorReport], DirNamesMixin):
"custom_metric": {"name": "Custom metric", "icon": ""},
}

_METRIC_ALIASES: dict[str, str] = {
"mean_squared_error": "neg_mean_squared_error",
"mean_absolute_error": "neg_mean_absolute_error",
"root_mean_squared_error": "neg_root_mean_squared_error",
"mean_absolute_percentage_error": "neg_mean_absolute_percentage_error",
"median_absolute_error": "neg_median_absolute_error",
"log_loss": "neg_log_loss",
"brier_score": "neg_brier_score",
"mean_poisson_deviance": "neg_mean_poisson_deviance",
"mean_gamma_deviance": "neg_mean_gamma_deviance",
}

def __init__(self, parent: EstimatorReport) -> None:
super().__init__(parent)

Expand Down Expand Up @@ -208,7 +220,8 @@ def summarize(
for metric_name, metric_ in zip(metric_names, metrics, strict=True):
if isinstance(metric_, str) and metric_ not in self._score_or_loss_info:
try:
metric_ = sklearn.metrics.get_scorer(metric_)
resolved_metric = self._METRIC_ALIASES.get(metric_, metric_)
metric_ = sklearn_metrics.get_scorer(resolved_metric)
except ValueError as err:
raise ValueError(
f"Invalid metric: {metric_!r}. "
Expand Down
50 changes: 50 additions & 0 deletions skore/tests/unit/reports/estimator/metrics/test_metric_aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pandas as pd
import pytest
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

from skore import EstimatorReport


@pytest.fixture
def linear_regression_with_test():
X, y = make_regression(n_samples=100, n_features=5, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
regressor = LinearRegression().fit(X_train, y_train)
return regressor, X_test, y_test


def test_metric_aliases_without_neg_prefix(linear_regression_with_test):
"""Check that metrics can be passed without the 'neg_' prefix and are
automatically resolved to their 'neg_' prefixed sklearn scorer equivalent.
This is the fix for https://github.com/probabl-ai/skore/issues/2607
"""
regressor, X_test, y_test = linear_regression_with_test
report = EstimatorReport(regressor, X_test=X_test, y_test=y_test)

display = report.metrics.summarize(
metric=["mean_squared_error", "mean_absolute_error", "root_mean_squared_error"]
)

result = display.frame()
assert isinstance(result, pd.DataFrame)
assert "Mean Squared Error" in result.index
assert "Mean Absolute Error" in result.index
assert "Root Mean Squared Error" in result.index


def test_metric_aliases_same_result_as_neg_prefix(linear_regression_with_test):
"""Check that passing 'mean_squared_error' gives the same score as
passing 'neg_mean_squared_error'.
"""
regressor, X_test, y_test = linear_regression_with_test
report = EstimatorReport(regressor, X_test=X_test, y_test=y_test)

display_with_neg = report.metrics.summarize(metric=["neg_mean_squared_error"])
display_without_neg = report.metrics.summarize(metric=["mean_squared_error"])

score_with_neg = display_with_neg.frame().values[0][0]
score_without_neg = display_without_neg.frame().values[0][0]

assert score_with_neg == pytest.approx(score_without_neg)
4 changes: 3 additions & 1 deletion sphinx/user_guide/reporters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ regression). Nevertheless, you can specify the metrics you want to compute thank
`scoring` parameter. We accept different types:

1. A string that corresponds to a scikit-learn scorer name or a built-in `skore`
metric name,
metric name. For error metrics, you can pass the name with or without the
``neg_`` prefix (e.g., ``"mean_squared_error"`` or ``"neg_mean_squared_error"``
are both valid),

2. A callable,

Expand Down
Loading