[R] Standard error for the area under a smoothed ROC curve?

Frank E Harrell Jr f.harrell at vanderbilt.edu
Wed Jan 12 20:09:33 CET 2005


Dan Bolser wrote:
> On Wed, 12 Jan 2005, Frank E Harrell Jr wrote:
> 
> 
>>Dan Bolser wrote:
>>
>>>Hello, 
>>>
>>>I am making some use of ROC curve analysis. 
>>>
>>>I find much help on the mailing list, and I have used the Area Under the
>>>Curve (AUC) functions from the ROC function in the bioconductor project...
>>>
>>>http://www.bioconductor.org/repository/release1.5/package/Source/
>>>ROC_1.0.13.tar.gz 
>>>
>>>However, I read here...
>>>
>>>http://www.medcalc.be/manual/mpage06-13b.php
>>>
>>>"The 95% confidence interval for the area can be used to test the
>>>hypothesis that the theoretical area is 0.5. If the confidence interval
>>>does not include the 0.5 value, then there is evidence that the laboratory
>>>test does have an ability to distinguish between the two groups (Hanley &
>>>McNeil, 1982; Zweig & Campbell, 1993)."
>>>
>>>But aside from early on the above article is short on details. Can anyone
>>>tell me how to calculate the CI of the AUC calculation?
>>>
>>>
>>>I read this...
>>>
>>>http://www.bioconductor.org/repository/devel/vignette/ROCnotes.pdf
>>>
>>>Which talks about resampling (by showing R code), but I can't understand
>>>what is going on, or what is calculated (the example given is specific to
>>>microarray analysis I think).
>>>
>>>I think a general AUC CI function would be a good addition to the ROC
>>>package.
>>>
>>>
>>>
>>>
>>>One more thing, in calculating the AUC I see the splines function is
>>>recomended over the approx function. Here...
>>>
>>>http://tolstoy.newcastle.edu.au/R/help/04/10/6138.html
>>>
>>>How would I rewrite the following AUC functions (adapted from bioconductor
>>>source) to use splines (or approxfun or splinefun) ...
>>>
>>>
>>>
>>>>spe # Specificity
>>>
>>> [1] 0.02173913 0.13043478 0.21739130 0.32608696 0.43478261 0.54347826
>>> [7] 0.65217391 0.76086957 0.89130435 1.00000000 1.00000000 1.00000000
>>>[13] 1.00000000
>>>
>>>
>>>
>>>>sen # Sensitivity
>>>
>>> [1] 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000 0.9302326 0.8139535
>>> [8] 0.6976744 0.5581395 0.4418605 0.3488372 0.2325581 0.1162791
>>>
>>>trapezint(1-spe,sen)
>>>my.integrate(1-spe,sen)
>>>
>>>## Functions
>>>## Nicked (and modified) from the ROC function in bioconductor.
>>>"trapezint" <-
>>>function (x, y, a = 0, b = 1)
>>>{
>>>    if (x[1] > x[length(x)]) {
>>>      x <- rev(x)
>>>      y <- rev(y)
>>>    }
>>>    y <- y[x >= a & x <= b]
>>>    x <- x[x >= a & x <= b]
>>>    if (length(unique(x)) < 2)
>>>        return(NA)
>>>    ya <- approx(x, y, a, ties = max, rule = 2)$y
>>>    yb <- approx(x, y, b, ties = max, rule = 2)$y
>>>    x <- c(a, x, b)
>>>    y <- c(ya, y, yb)
>>>    h <- diff(x)
>>>    lx <- length(x)
>>>    0.5 * sum(h * (y[-1] + y[-lx]))
>>>}
>>>
>>>"my.integrate" <-
>>>function (x, y, t0 = 1)
>>>{
>>>    f <- function(j) approx(x,y,j,rule=2,ties=max)$y
>>>    integrate(f, 0, t0)$value
>>>}
>>>
>>>
>>>
>>>
>>>
>>>Thanks for any pointers,
>>>Dan.
>>
>>I don't see why the above formulas are being used.  The 
>>Bamber-Hanley-McNeil-Wilcoxon-Mann-Whitney nonparametric method works 
>>great.  Just get the U statistic (concordance probability) used in 
>>Wilcoxon.  As Somers' Dxy rank correlation coefficient is 2*(1-C) where 
>>C is the concordance or ROC area, the Hmisc package function rcorr.cens 
>>uses U statistic methods to get the standard error of Dxy.  You can 
>>easily translate this to a standard error of C.
> 
> 
> 
> I am sure I could do this easily, except I can't. 
> 
> The good thing about ROC is that I understand it (I can see it). I know
> why the area means what it means, and I could even imagine how sampling
> the data could give a CI on the area. 
> 
> However, I don't know why "the area under the ROC curve is well known to
> be equivalent to the numerator of the Mann-Whitney U statistic" - from
> 
> http://www.bioconductor.org/repository/devel/vignette/ROCnotes.pdf
> 
> 
> Nor do I know how to calculate "the numerator of the Mann-Whitney U
> statistic".

This is clear in the original Bamber or Hanley-McNeil articles.  The ROC 
area is a linear translation of the mean rank of predicted values in one 
of the two outcome groups.  The little somers2 function in Hmisc shows this:

##S function somers2
##
##    Calculates concordance probability and Somers'  Dxy  rank  correlation
##    between  a  variable  X  (for  which  ties are counted) and a binary
##    variable Y (having values 0 and 1, for which ties are not  counted).
##    Uses short cut method based on average ranks in two groups.
##
##    Usage:
##
##         somers2(X,Y)
##
##    Returns vector whose elements are C Index, Dxy, n and missing, where
##    C Index is the concordance probability and Dxy=2(C Index-.5).
##
##    F. Harrell 28 Nov 90     6 Apr 98: added weights

somers2 <- function(x, y, weights=NULL, normwt=FALSE, na.rm=TRUE) {
   if(length(y)!=length(x))stop("y must have same length as x")
   y <- as.integer(y)
   wtpres <- length(weights)
   if(wtpres && (wtpres != length(x)))
         stop('weights must have same length as x')
   if(na.rm) {
         miss <- if(wtpres) is.na(x + y + weights) else is.na(x + y)
         nmiss <- sum(miss)
         if(nmiss>0)     {
           miss <- !miss
           x <- x[miss]
           y <- y[miss]
           if(wtpres) weights <- weights[miss]
         }
   } else nmiss <- 0
    u <- sort(unique(y))
   if(any(y %nin% 0:1)) stop('y must be binary')  ## 7dec02
   if(wtpres) {
         if(normwt) weights <- length(x)*weights/sum(weights)
         n <- sum(weights)
   } else n <- length(x)

   if(n<2)stop("must have >=2 non-missing observations")

   n1 <- if(wtpres)sum(weights[y==1]) else sum(y==1)
   if(n1==0 || n1==n) return(c(C=NA,Dxy=NA,n=n,Missing=nmiss))  ## 7dec02
   ## added weights > 0 30Mar00
   mean.rank <- if(wtpres) mean(wtd.rank(x, weights, na.rm=FALSE)[weights >
                                                       0 & y==1]) else
                  mean(rank(x)[y==1])
   c.index <- (mean.rank - (n1+1)/2)/(n-n1)
   dxy <- 2*(c.index-.5)
   r <- c(c.index, dxy, n, nmiss)
   names(r) <- c("C","Dxy","n","Missing")
   r
}

Just ignore all the stuff with weights.  The ROC area is given by 
c.index in the 5th line from the end.  But somers2 does not compute its 
standard error.

A standard text on nonparametric tests shows how to compute the 
Wilcoxon-M-W test stat based on mean(rank(x in y==1 group)).

Frank

> 
> Can you point me at some ? pages or tutorials or even give an example of
> what you suggested so I can try to follow it through?
> 
> I tried the following...
> 
> x <- rnorm(100,5,1)    # REAL NEGATIVE
> #
> y <- rnorm(100,8,1)    # REAL POSITIVE
> 
> t <- wilcox.test(x,y,paired=FALSE,conf.int=0.95)
> 
> 
>>t
> 
> 
> 	Wilcoxon rank sum test with continuity correction
> 
> data:  x and y 
> W = 132, p-value < 2.2e-16
> alternative hypothesis: true mu is not equal to 0 
> 95 percent confidence interval:
>  -3.232207 -2.664620 
> sample estimates:
> difference in location 
>              -2.957496 
> 
> 
> And from ?wilcox.test ...
> 
> "if both x and y are given and paired is FALSE, a Wilcoxon rank sum test
> (equivalent to the Mann-Whitney test) is carried out."
> 
> 
> But I don't know what to do next. Sorry for all the questions, but I am a
> dumb biologist.
> 
> Thanks for the help, Dan.
> 
> 
> 
> 
>>Frank
>>
>>
> 
> 
> 


-- 
Frank E Harrell Jr   Professor and Chair           School of Medicine
                      Department of Biostatistics   Vanderbilt University




More information about the R-help mailing list