Introdução

A curva característica de operação do receptor (Receiver Operating Characteristic, ROC) é usada para avaliar a precisão de uma medição contínua para prever um resultado binário. Na medicina, as curvas ROC têm uma longa história de uso para avaliar os testes de diagnóstico em radiologia e diagnósticos gerais. As curvas ROC também foram usadas por um longo tempo na teoria da detecção de sinais.

A precisão de um teste de diagnóstico pode ser avaliada considerando os dois tipos possíveis de erros: falsos positivos e falsos negativos. Para uma medição contínua que denotamos como \(M\), a convenção dita que um teste positivo é definido como \(M\) excedendo algum limiar fixo \(c\): \(M> c\). Em referência ao resultado binário que denotamos como \(D\), um bom resultado do teste é quando o teste é positivo entre um indivíduo que realmente tem uma doença: \(D = 1\). Um mau resultado é quando o teste é positivo entre um indivíduo que não tem a doença \(D = 0\).

Formalmente, para um corte fixo \(c\), a verdadeira fração positiva é a probabilidade de um teste positivo entre a população doente: \[\begin{equation*} TPF(c) = P\big(M> c | D = 1\big) \end{equation*}\] e a falsa fração positiva é a probabilidade de um teste positivo entre a população saudável: \[\begin{equation*} FPF(c) = P\big(M> c | D = 0\big) \end{equation*}\]

Como o corte \(c\) não é geralmente fixo antecipadamente, podemos traçar o \(TPF\) contra o \(FPF\) para todos os valores possíveis de \(c\). Isto é exatamente o que é a curva ROC, \(FPF(c)\) no eixo \(x\) e \(TPF(c)\) ao longo do eixo \(y\).

Vamos mostrar como criar e interpretar a curva ROC utilizando o pacote de funções plotROC. Esta apresentação está baseada na vinheta do pacote R mencionado, programado por Michael C. Sachs e Robert W. Corty, versão 2.2.1 de 2018-06-01. The MIT License (MIT). Copyright (c) 2017 Michael C Sachs. http://sachsmc.github.io/plotROC-paper/Paper/sachs2015plotROC.pdf

Exemplo

Começamos criando um conjunto de dados que servirá de exemplo. Existem 2 marcadores, um que é moderadamente preditivo e um outro que não é tão preditivo.

library(plotROC)
set.seed(2529)
D.ex <- rbinom(200, size = 1, prob = .5)
M1 <- rnorm(200, mean = D.ex, sd = .65)
M2 <- rnorm(200, mean = D.ex, sd = 1.5)

test <- data.frame(D = D.ex, D.str = c("Saudável", "Doente")[D.ex + 1], 
                   M1 = M1, M2 = M2, stringsAsFactors = FALSE)
head(test)
##   D    D.str         M1          M2
## 1 1   Doente 1.48117155 -2.50636605
## 2 1   Doente 0.61994478  1.46861033
## 3 0 Saudável 0.57613345  0.07532573
## 4 1   Doente 0.85433197  2.41997703
## 5 0 Saudável 0.05258342  0.01863718
## 6 1   Doente 0.66703989  0.24732453

Observemos os dados.

par(mfrow=c(1,2), mar = c(4,5,1,1), pch=19)
plot(test$M1,test$D, ylab="", xlab="Marcador M1")
text(0,0.1,"Indivíduos saudáveis"); text(1,0.9,"Indivíduos doentes")
grid()
plot(test$M2,test$D, ylab="", xlab="Marcador M2")
text(0,0.1,"Indivíduos saudáveis"); text(1,0.9,"Indivíduos doentes")
grid()

Observado a figura acima percebemos que o marcador \(M1\) é um pouco melhor preditivo do que o marcador \(M2\).

A Curva ROC

Em seguida, utilizando a função ggplot para definir a estética e a função geom_roc para adicionar uma camada com a curva ROC. A função geom_roc requer a informação d para informar o estado da doença, e m para o marcador. O estado da doença não precisa ser codificado como 0/1, mas se não for, o stat_roc assume (com um aviso) que o valor mais baixo no pedido significam o estado livre de doenças.

basicplot <- ggplot(test, aes(d = D, m = M1)) + geom_roc()
basicplot

A camada geom_roc inclui a linha da curva ROC combinada com pontos e rótulos para exibir os valores do biomarcador nos diferentes pontos de corte. Ele aceita o argumento n.cuts para definir o número de pontos de corte a serem exibidos ao longo da curva. As etiquetas podem ser supressionadas usando n.cuts = 0 ou labels = FALSE. O tamanho dos rótulos e o número de dígitos significativos podem ser ajustados com as opcções labelsize e labelround, respectivamente.

ggplot(test, aes(d = D, m = M1)) + geom_roc(n.cuts = 0)

Também existe a função style_roc que pode ser adicionado a um ggplot que contenha ém uma camada a curva ROC. Isso adiciona uma diretriz diagonal, define os rótulos do eixo e ajusta as linhas de grade maiores e menores. A função direct_label opera em um objeto ggplot, adicionando uma etiqueta direta ao gráfico. Esta opção tenta selecionar inteligentemente um local apropriado para o rótulo, mas o local pode ser ajustado com nudg_x, nudge_y e label.angle. Se o argumento de labels for NULL, ele levará a estética especificada.

styledplot <- basicplot + style_roc()
styledplot

direct_label(basicplot, labels = "Biomarcador M1", nudge_y = -.2) + style_roc()

Regiões de confiança

É comum calcular regiões de confiança para pontos na curva ROC usando o método exato de Clopper and Pearson (1934). Resumidamente, os intervalos de confiança exatos são calculados para o \(FPF\) e \(TPF\) separadamente, cada um no nível de confiança \(1-\sqrt{1-\alpha}\). Baseado no resultado 2.4 de Pepe (2003), o produto transversal desses intervalos produz uma região de confiança retangular \(100*(1-\alpha)\) por cento para o par.

Isso é implementado no stat_rocci e exibido como uma camada geom_rocci. Estes ambos exigem a mesma estética que o Roc geom, \(d\) para o status da doença e \(m\) para o marcador. Por padrão, um conjunto de 3 pontos uniformemente espaçados ao longo da curva é escolhido para exibir regiões de confiança. Você pode selecionar pontos passando um vetor de valores no intervalo de \(m\) para o argumento ci.at. Por padrão, o nível de significância \(\alpha\) é definido como 0,05, isso pode ser alterado usando a opção sig.level.

styledplot + geom_rocci(sig.level = .01)

ggplot(test, aes(d = D, m = M1)) + geom_roc(n.cuts = 0) +
  geom_rocci(ci.at = quantile(M1, c(.1, .4, .5, .6, .9))) + style_roc()

Múltiplas curvas ROC.

Se você tiver fatores de agrupamento no seu conjunto de dados ou tiver vários marcadores medidos nos mesmos assuntos, talvez desejará mostrar várias curvas ROC no mesmo gráfico. ploROC suporta totalmente facetagem e agrupamento feito por ggplot2. No exemplo de dados, temos 2 marcadores medidos de maneira pareada:

head(test)
##   D    D.str         M1          M2
## 1 1   Doente 1.48117155 -2.50636605
## 2 1   Doente 0.61994478  1.46861033
## 3 0 Saudável 0.57613345  0.07532573
## 4 1   Doente 0.85433197  2.41997703
## 5 0 Saudável 0.05258342  0.01863718
## 6 1   Doente 0.66703989  0.24732453

Esses dados estão em formato grande, com 2 marcadores passando por 2 colunas. O ggplot requer um formato longo, com o resultado do marcador em uma única coluna e uma terceira variável identificando o marcador. É fornecida então a função melt_roc para executar esta transformação. Os argumentos são o arquivo de dados, um nome ou índice que identificam a coluna do estado da doença e um vetor de nomes ou índices que identificam os marcadores. Opcionalmente, o argumento de nomes fornece um vetor de nomes para atribuir ao marcador, substituindo seus nomes de colunas. O resultado é um arquivo de dados em formato longo.

longtest <- melt_roc(test, "D", c("M1", "M2"))
head(longtest)
##     D          M name
## M11 1 1.48117155   M1
## M12 1 0.61994478   M1
## M13 0 0.57613345   M1
## M14 1 0.85433197   M1
## M15 0 0.05258342   M1
## M16 1 0.66703989   M1

Em seguida, o conjunto de dados pode ser passado para a função ggplot com o nome do marcador fornecido como um agrupamento ou variável de facetagem.

ggplot(longtest, aes(d = D, m = M, color = name)) + geom_roc() + style_roc()

ou

ggplot(longtest, aes(d = D, m = M)) + geom_roc() + facet_wrap(~ name) + style_roc()

Bibliografia

  1. Clopper, C.J. and Pearson, E.S. (1934). The Use of Confidence or Fiducial Limits Illustrated in the Case of the Binomial. Biometrika, 26, 404-413. http://dx.doi.org/10.1093/biomet/26.4.404
  2. Pepe MS (2003). The statistical evaluation of medical tests for classification and prediction. Oxford University Press.