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

Code before:
        warnings.warn(msg, UndefinedMetricWarning)
        return float("nan")

    xp, _, device_ = get_namespace_and_device(y_proba)
    y_proba = check_array(
        y_proba, ensure_2d=False, dtype=supported_float_dtypes(xp, device=device_)
    )
    if sample_weight is not None:
        sample_weight = ensure_common_namespace_device(y_proba, sample_weight)[0]
    if y_proba.ndim == 1 or y_proba.shape[1] == 1:
        transformed_labels, y_proba = _validate_binary_probabilistic_prediction(
            y_true, y_proba, sample_weight, pos_label
        )
    else:
        transformed_labels, y_proba = _validate_multiclass_probabilistic_prediction(
            y_true, y_proba, sample_weight, labels
        )
    transformed_labels = xp.astype(transformed_labels, y_proba.dtype, copy=False)
    y_proba_null = _average(transformed_labels, axis=0, weights=sample_weight)
    y_proba_null = xp.tile(y_proba_null, (y_proba.shape[0], 1))

    # Scaling does not matter in D^2 score as it cancels out by taking the ratio.
    brier_score = _average(
        xp.sum((transformed_labels - y_proba) ** 2, axis=1),
        weights=sample_weight,
    )
    brier_score_null = _average(
        xp.sum((transformed_labels - y_proba_null) ** 2, axis=1),
        weights=sample_weight,
    )
    return float(1 - brier_score / brier_score_null)


Review comment (refactor):
Maybe we could add a `dtype` param to the one hot encoding helpers.

Code after:
    ----------
    .. [1] `Wikipedia entry for the Brier Skill Score (BSS)
            <https://en.wikipedia.org/wiki/Brier_score>`_.
    """
    check_consistent_length(y_proba, y_true, sample_weight)
    if _num_samples(y_proba) < 2:
        msg = "D^2 score is not well-defined with less than two samples."
        warnings.warn(msg, UndefinedMetricWarning)
        return float("nan")

    xp, _, device_ = get_namespace_and_device(y_proba)
    y_proba = check_array(
        y_proba, ensure_2d=False, dtype=supported_float_dtypes(xp, device=device_)
    )
    if sample_weight is not None:
        sample_weight = ensure_common_namespace_device(y_proba, sample_weight)[0]

    if y_proba.ndim == 1 or y_proba.shape[1] == 1:
        transformed_labels, y_proba = _validate_binary_probabilistic_prediction(
            y_true, y_proba, sample_weight, pos_label
        )
    else:
        transformed_labels, y_proba = _validate_multiclass_probabilistic_prediction(
            y_true, y_proba, sample_weight, labels
        )
    transformed_labels = xp.astype(transformed_labels, y_proba.dtype, copy=False)
    y_proba_null = _average(transformed_labels, axis=0, weights=sample_weight)
    y_proba_null = xp.tile(y_proba_null, (y_proba.shape[0], 1))

    # Scaling does not matter in D^2 score as it cancels out by taking the ratio.
    brier_score = _average(
        xp.sum((transformed_labels - y_proba) ** 2, axis=1),
        weights=sample_weight,
    )
    brier_score_null = _average(
        xp.sum((transformed_labels - y_proba_null) ** 2, axis=1),
        weights=sample_weight,
    )
    return float(1 - brier_score / brier_score_null)