auc_delong calculates the ROC AUC of every model on one test set
together with the variance and covariance of those AUCs, exactly rather
than by resampling. auc_ci() turns the result into confidence
intervals and auc_diff() into comparisons between models.
Arguments
- mdat
An
mdataobject created bymmdata()holding exactly one dataset. It can be omitted whenscoresandlabelsare given.- scores
A numeric vector, matrix, array, data frame, or list of scores. See
mmdata()for the accepted shapes.- labels
A numeric, character, logical, or factor vector of observed labels, or a list of such vectors.
- ...
Further arguments passed to
mmdata()whenscoresandlabelsare given instead ofmdat.
Value
An object of class aucdelong: a data frame of one row per
model, with the columns modnames, curvetypes, aucs and error,
the last being the standard error of the AUC. The covariance matrix of
the AUCs is attached as the cov attribute, and is what makes the
comparison in auc_diff() a paired one.
Details
The ROC AUC is a Mann-Whitney U statistic, so its variance follows from
the structural components of that statistic and needs no bootstrap. That
makes this the exact counterpart of auc_boot(): same input, same two
functions reading the result, no boot_n, no seed, nothing that changes
between two runs, and no floor under the p-value.
The ROC AUC only
There is no precision-recall counterpart of this. The ROC AUC is a
U statistic - the probability that a random positive outranks a random
negative - and everything below rests on that. The precision-recall AUC
is not one, and the interpolated area auc() reports is further from
being one still, so it has no analytic variance to report and does not
appear in the result.
auc_boot() remains the answer for the precision-recall AUC, and the
one to reach for whenever the precision-recall curve is the point. This
function is here because the ROC AUC is what a great many readers and
reviewers ask about by name, and because it is exact where the bootstrap
is approximate.
How the variance is calculated
Write m for the positives and n for the negatives. Each positive i
and each negative j contributes a structural component - the share of
the other class it beats:
where psi is 1 when the positive outranks the negative, 0.5 when they
are tied and 0 otherwise - the same half credit for a tie that the AUC
itself gives. The variance is then
and for two models on the same test set the covariance is the same
expression with the covariance of their components. Both are computed
from midranks rather than from all m * n comparisons, so the cost is a
sort rather than a product.
The components are taken from the ranks precrec already assigns, so
ties and NA scores are handled exactly as they are everywhere else in
the package and the AUC reported here is the one auc() reports.
What it assumes
The variance is an asymptotic one. It describes how the AUC would
move over repeated samples of the same size, and the interval built from
it is a normal one, so both get better as the test set grows. On a small
or badly imbalanced test set the percentile interval of auc_boot() is
the safer reading, and comparing the two is a cheap way to find out
whether the sample is large enough for this one.
See also
auc_boot() for the resampling counterpart, which also covers
the precision-recall AUC, auc_ci() for the intervals and
auc_diff() for comparing models.
Examples
## One test set, two models
samps <- create_sim_samples(1, 100, 100, c("poor_er", "good_er"))
mdat <- mmdata(samps[["scores"]], samps[["labels"]],
modnames = samps[["modnames"]]
)
delong <- auc_delong(mdat)
delong
#> modnames curvetypes aucs error
#> 1 poor_er ROC 0.7845 0.03210423
#> 2 good_er ROC 0.8512 0.02794278
auc_ci(delong)
auc_diff(delong)