Repository: scikit-learn/scikit-learn
File: sklearn/metrics/_regression.py (Python)

Code before:
    xp, _, device_ = get_namespace_and_device(
        y_true, y_pred, sample_weight, multioutput
    )
    _, y_true, y_pred, sample_weight, multioutput = (
        _check_reg_targets_with_floating_dtype(
            y_true, y_pred, sample_weight, multioutput, xp=xp
        )
    )

    if _num_samples(y_pred) < 2:
        msg = "D^2 score is not well-defined with less than two samples."
        warnings.warn(msg, UndefinedMetricWarning)
        return float("nan")

    numerator = mean_pinball_loss(
        y_true,
        y_pred,
        sample_weight=sample_weight,
        alpha=alpha,
        multioutput="raw_values",
    )

    if sample_weight is None:
        percentile = np.percentile(
            _convert_to_numpy(y_true, xp=xp), q=alpha * 100, axis=0
        )
        percentile = xp.asarray(percentile, device=device_)
        y_quantile = xp.tile(percentile, (y_true.shape[0], 1))
    else:
        y_quantile = xp.tile(
            _weighted_percentile(
                y_true,
                sample_weight=sample_weight,
                percentile_rank=alpha * 100,
                average=True,
                xp=xp,
            ),
            (y_true.shape[0], 1),
        )

    denominator = mean_pinball_loss(
        y_true,
        y_quantile,
        sample_weight=sample_weight,
        alpha=alpha,
        multioutput="raw_values",
    )

    return _assemble_fraction_of_explained_deviance(
        numerator=numerator,
        denominator=denominator,

Review comment (bug):
Instead of converting to NumPy, I would rather always call `_weighted_percentile` with unit weights instead. That might cause a slight performance degradation (for NumPy inputs), but I don't think those functions are that performance critical in practice, and code simplicity might trump the slight performance improvement here.

Calling `_weighted_percentile` with unit weights when `sample_weight is None` shoud fix the `test_multioutput_sample_weight_invariance` failure.


Code after:
        y_true, y_pred, sample_weight, multioutput
    )
    _, y_true, y_pred, sample_weight, multioutput = (
        _check_reg_targets_with_floating_dtype(
            y_true, y_pred, sample_weight, multioutput, xp=xp
        )
    )

    if _num_samples(y_pred) < 2:
        msg = "D^2 score is not well-defined with less than two samples."
        warnings.warn(msg, UndefinedMetricWarning)
        return float("nan")

    numerator = mean_pinball_loss(
        y_true,
        y_pred,
        sample_weight=sample_weight,
        alpha=alpha,
        multioutput="raw_values",
    )

    if sample_weight is None:
        sample_weight = xp.ones([y_true.shape[0]], dtype=y_true.dtype, device=device_)

    y_quantile = xp.tile(
        _weighted_percentile(
            y_true,
            sample_weight=sample_weight,
            percentile_rank=alpha * 100,
            average=True,
            xp=xp,
        ),
        (y_true.shape[0], 1),
    )

    denominator = mean_pinball_loss(
        y_true,
        y_quantile,
        sample_weight=sample_weight,
        alpha=alpha,
        multioutput="raw_values",
    )

    return _assemble_fraction_of_explained_deviance(
        numerator=numerator,
        denominator=denominator,
        n_outputs=y_true.shape[1],
        multioutput=multioutput,
        force_finite=True,
        xp=xp,
        device=device_,