Repository: Lightning-AI/pytorch-lightning
File: pytorch_lightning/metrics/functional/classification.py (Python)

Code before:
        max_fpr: If not `None`, calculates standardized partial AUC over the
            range [0, max_fpr]. Should be a float between 0 and 1 (Default: None)

    Return:
        Tensor containing ROCAUC score

    Example:

        >>> x = torch.tensor([0, 1, 2, 3])
        >>> y = torch.tensor([0, 1, 1, 0])
        >>> auroc(x, y)
        tensor(0.5000)
    """
    if any(target > 1):
        raise ValueError('AUROC metric is meant for binary classification, but'
                         ' target tensor contains value different from 0 and 1.'
                         ' Use `multiclass_auroc` for multi class classification.')

    def _auroc(pred, target, sample_weight, pos_label, max_fpr):
        if max_fpr is None or max_fpr == 1:
            fpr, tpr, _ = __roc(pred, target, sample_weight, pos_label)
            return auc(fpr, tpr)
        if max_fpr <= 0 or max_fpr > 1:
            raise ValueError("Expected max_fpr in range (0, 1], got: %r" % max_fpr)
        if LooseVersion(torch.__version__) < LooseVersion('1.6.0'):
            raise RuntimeError('`max_fpr` argument requires `torch.bucketize` which '
                               ' is not available below PyTorch version 1.6')

        fpr, tpr, _ = __roc(pred, target, sample_weight, pos_label)
        max_fpr = torch.tensor(max_fpr, device=fpr.device)
        # Add a single point at max_fpr and interpolate its tpr value
        stop = torch.bucketize(max_fpr, fpr, out_int32=True, right=True)
        weight = (max_fpr - fpr[stop - 1]) / (fpr[stop] - fpr[stop - 1])
        interp_tpr = torch.lerp(tpr[stop - 1], tpr[stop], weight)
        tpr = torch.cat([tpr[:stop], interp_tpr.view(1)])
        fpr = torch.cat([fpr[:stop], max_fpr.view(1)])

        # Compute partial AUC
        partial_auc = auc(fpr, tpr)

        # McClish correction: standardize result to be 0.5 if non-discriminant
        # and 1 if maximal
        min_area = 0.5 * max_fpr**2
        max_area = max_fpr
        return 0.5 * (1 + (partial_auc - min_area) / (max_area - min_area))

    return _auroc(pred=pred, target=target, sample_weight=sample_weight, pos_label=pos_label, max_fpr=max_fpr)


def multiclass_auroc(
        pred: torch.Tensor,

Review comment (suggestion):
```suggestion
            raise RuntimeError('`max_fpr` argument requires `torch.bucketize` which'
```

Code after:
            range [0, max_fpr]. Should be a float between 0 and 1.

    Return:
        Tensor containing ROCAUC score

    Example:

        >>> x = torch.tensor([0, 1, 2, 3])
        >>> y = torch.tensor([0, 1, 1, 0])
        >>> auroc(x, y)
        tensor(0.5000)
    """
    if any(target > 1):
        raise ValueError('AUROC metric is meant for binary classification, but'
                         ' target tensor contains value different from 0 and 1.'
                         ' Use `multiclass_auroc` for multi class classification.')

    if max_fpr is None or max_fpr == 1:
        fpr, tpr, _ = __roc(pred, target, sample_weight, pos_label)
        return auc(fpr, tpr)
    if not (isinstance(max_fpr, float) and 0 < max_fpr <= 1):
        raise ValueError(f"`max_fpr` should be a float in range (0, 1], got: {max_fpr}")
    if LooseVersion(torch.__version__) < LooseVersion('1.6.0'):
        raise RuntimeError('`max_fpr` argument requires `torch.bucketize` which'
                           ' is not available below PyTorch version 1.6')

    fpr, tpr, _ = __roc(pred, target, sample_weight, pos_label)
    max_fpr = torch.tensor(max_fpr, device=fpr.device)
    # Add a single point at max_fpr and interpolate its tpr value
    stop = torch.bucketize(max_fpr, fpr, out_int32=True, right=True)
    weight = (max_fpr - fpr[stop - 1]) / (fpr[stop] - fpr[stop - 1])
    interp_tpr = torch.lerp(tpr[stop - 1], tpr[stop], weight)
    tpr = torch.cat([tpr[:stop], interp_tpr.view(1)])
    fpr = torch.cat([fpr[:stop], max_fpr.view(1)])

    # Compute partial AUC
    partial_auc = auc(fpr, tpr)

    # McClish correction: standardize result to be 0.5 if non-discriminant
    # and 1 if maximal
    min_area = 0.5 * max_fpr ** 2
    max_area = max_fpr
    return 0.5 * (1 + (partial_auc - min_area) / (max_area - min_area))


def multiclass_auroc(
        pred: torch.Tensor,
        target: torch.Tensor,
        sample_weight: Optional[Sequence] = None,
        num_classes: Optional[int] = None,
) -> torch.Tensor: