I am running a binary classifier at the moment. When I plot the ROC curve I get a good lift at the beginning then it changes direction and crosses the diagonal then of course back up, making the curve a tilted S like shape.

What can be an interpretation/explanation to this effect?


  • 1
    $\begingroup$ What made you care about an ROC curve? What made you choose a classifier instead of a direct probability model? $\endgroup$ Commented Mar 28, 2013 at 12:19

3 Answers 3


You get a nice symmetric ROC plot only when standard deviations for both outcomes are the same. If they are rather different then you may get exactly the result you describe.

The following Mathematica code demonstrates this. We assume that a target yields a normal distribution in response space, and that noise also yields a normal distribution, but a displaced one. The ROC parameters are determined by the area below the Gaussian curves to the left or right of a decision criterion. Varying this criterion describes the ROC curve.

 ParametricPlot[{CDF[NormalDistribution[4, \[Sigma]], c], 
                 CDF[NormalDistribution[0, 3], c]
                }, {c, -10, 10}, 
                Frame -> True, 
                Axes -> None, PlotRange -> {{0, 1}, {0, 1}}, 
                Epilog -> Line[{{0, 0}, {1, 1}}]], 
 {{\[Sigma], 3}, 0.1, 10, Appearance -> "Labeled"}]

This is with equal standard deviations: enter image description here

This is with rather distinct ones:

enter image description here

or with a few more parameters to play with:

 ParametricPlot[{CDF[NormalDistribution[\[Mu]1, \[Sigma]1], c], 
   CDF[NormalDistribution[\[Mu]2, \[Sigma]2], c]}, {c, -100, 100}, 
  Frame -> True, Axes -> None, PlotRange -> {{0, 1}, {0, 1}}, 
  Epilog -> Line[{{0, 0}, {1, 1}}]], {{\[Mu]1, 0}, 0, 10, 
  Appearance -> "Labeled"},
 {{\[Sigma]1, 4}, 0.1, 20, Appearance -> "Labeled"},
 {{\[Mu]2, 5}, 0, 10, Appearance -> "Labeled"},
 {{\[Sigma]2, 4}, 0.1, 20, Appearance -> "Labeled"}]

enter image description here


(The answers by @Sjoerd C. de Vries and @Hrishekesh Ganu are correct. I thought I could nonetheless present the ideas another way, which may help some people.)

You can get a ROC like that if your model is misspecified. Consider the example below (coded in R), which is adapted from my answer here: How to use boxplots to find the point where values are more likely to come from different conditions?

## data
Cond.1 = c(2.9, 3.0, 3.1, 3.1, 3.1, 3.3, 3.3, 3.4, 3.4, 3.4, 3.5, 3.5, 3.6, 3.7, 3.7,
           3.8, 3.8, 3.8, 3.8, 3.9, 4.0, 4.0, 4.1, 4.1, 4.2, 4.4, 4.5, 4.5, 4.5, 4.6,
           4.6, 4.6, 4.7, 4.8, 4.9, 4.9, 5.5, 5.5, 5.7)
Cond.2 = c(2.3, 2.4, 2.6, 3.1, 3.7, 3.7, 3.8, 4.0, 4.2, 4.8, 4.9, 5.5, 5.5, 5.5, 5.7,
           5.8, 5.9, 5.9, 6.0, 6.0, 6.1, 6.1, 6.3, 6.5, 6.7, 6.8, 6.9, 7.1, 7.1, 7.1,
           7.2, 7.2, 7.4, 7.5, 7.6, 7.6, 10, 10.1, 12.5)
dat    = stack(list(cond1=Cond.1, cond2=Cond.2))
ord    = order(dat$values)
dat    = dat[ord,]  # now the data are sorted

## logistic regression models
lr.model1 = glm(ind~values,             dat, family="binomial")  # w/o a squared term
lr.model2 = glm(ind~values+I(values^2), dat, family="binomial")  # w/  a squared term
lr.preds1 = predict(lr.model1, data.frame(values=seq(2.3,12.5,by=.1)), type="response")
lr.preds2 = predict(lr.model2, data.frame(values=seq(2.3,12.5,by=.1)), type="response")

## here I plot the data & the 2 models
  with(dat, plot(values, ifelse(ind=="cond2",1,0), 
                 ylab="predicted probability of condition2"))
  lines(seq(2.3,12.5,by=.1), lr.preds1, lwd=2, col="red")
  lines(seq(2.3,12.5,by=.1), lr.preds2, lwd=2, col="blue")
  legend("bottomright", legend=c("model 1", "model 2"), lwd=2, col=c("red", "blue"))

enter image description here

It's easy to see that the red model is missing the structure of the data. We can see what the ROC curves look like when plotted below:

library(ROCR)  # we'll use this package to make the ROC curve

## these are necessary to make the ROC curves
pred1 = with(dat, prediction(fitted(lr.model1), ind))
pred2 = with(dat, prediction(fitted(lr.model2), ind))
perf1 = performance(pred1, "tpr", "fpr")
perf2 = performance(pred2, "tpr", "fpr")

## here I plot the ROC curves
  plot(perf1, col="red",  lwd=2)
  plot(perf2, col="blue", lwd=2, add=T)
  abline(0,1, col="gray")
  legend("bottomright", legend=c("model 1", "model 2"), lwd=2, col=c("red", "blue"))

enter image description here

We can now see that, for the misspecified (red) model, when the false positive rate becomes greater than $80\%$, the false positive rate increases more quickly than the true positive rate. Looking at the models above, we see that that point is where the red and blue lines cross at the lower left.


Having a string of negative instances in the part of the curve with high FPR can create this kind of a curve. This is ok as long as you are using the right algorithm for generating the ROC curve.

The condition where you have a set of 2m points half of which are positive and half are negative-all having exactly the same score for your model is tricky. If while sorting the points based on the score (standard procedure in plotting ROC) all the negative examples are encountered first, this will cause your ROC curve to stay flat and move to the right.This paper talks about how to take care of such issues:

Fawcett| Plotting ROC curves


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.