2015-02-19 2 views
5

Sto provando a utilizzare stat_ecdf() per tracciare i risultati cumulativi in ​​funzione di un punteggio di classifica creato da un modello predittivo.In R ggplot2, include stat_ecdf() endpoint (0,0) e (1,1)

#libraries 
require(ggplot2) 
require(scales) 

# fake data for reproducibility 
set.seed(123) 
n <- 200 
df <- data.frame(model_score= rexp(n=n,rate=1:n), 
       obs_set= sample(c("training","validation"),n,replace=TRUE)) 
df$model_rank <- rank(df$model_score)/n 
df$target_outcome <- rbinom(n,1,1-df$model_rank) 

# Plot Gain Chart using stat_ecdf() 
ggplot(subset(df,target_outcome==1),aes(x = model_rank)) + 
    stat_ecdf(aes(colour = obs_set), size=1) + 
    scale_x_continuous(limits=c(0,1), labels=percent,breaks=seq(0,1,.1)) + 
    xlab("Model Percentile") + ylab("Percent of Target Outcome") + 
    scale_y_continuous(limits=c(0,1), labels=percent) + 
    geom_segment(aes(x=0,y=0,xend=1,yend=1), 
       colour = "gray", linetype="longdash", size=1) + 
    ggtitle("Gain Chart") 

enter image description here

Tutto quello che voglio fare è forzare l'ECDF per iniziare a (0,0) e alla fine a (1,1) in modo che non ci siano spazi all'inizio o alla fine del curva. Se possibile, mi piacerebbe farlo nella sintassi di ggplot2, ma mi accontenterei di una soluzione intelligente.

@Henrik questo non è un duplicato di this question, perché ho già definito i miei limiti con scale_x_ e _y_continuous(), e l'aggiunta di expand_limits() non fare nulla. Non è l'origine del PLOT ma gli endpoint di stat_ecdf() che devono essere corretti.

+0

@Henrik - leggi la questione. Guarda la mia trama. Chiaramente la griglia include già (0,0) e (1,1), punti che sono inclusi su 'geom_segment()', quindi * non * è una questione di impostare i limiti dell'oggetto trama. La domanda ha a che fare con il dominio dell'oggetto 'stat_ecdf()' come indicato nel titolo della mia domanda. Guarda quello che consideri un post duplicato. Non è affatto collegato. – C8H10N4O2

+0

Puoi dirmi come hai fatto per avere percentuali sull'asse y? –

+1

@MostafaRifi '+ scale_y_continuous (etichette = cento)' e non dimenticate 'biblioteca (scale)' – C8H10N4O2

risposta

1

Purtroppo, la definizione di stat_ecdf non dà spazio di manovra qui; determina gli endpoint internamente.

c'è una soluzione un po 'avanzato. Con l'ultima versione di ggplot2 (devtools::install_github("hadley/ggplot2")), l'estensibilità è migliorata, al punto in cui è possibile ignorare questo comportamento, ma non senza un po 'di testo standard.

stat_ecdf2 <- function(mapping = NULL, data = NULL, geom = "step", 
         position = "identity", n = NULL, show.legend = NA, 
         inherit.aes = TRUE, minval=NULL, maxval=NULL,...) { 
    layer(
    data = data, 
    mapping = mapping, 
    stat = StatEcdf2, 
    geom = geom, 
    position = position, 
    show.legend = show.legend, 
    inherit.aes = inherit.aes, 
    stat_params = list(n = n, minval=minval,maxval=maxval), 
    params = list(...) 
) 
} 


StatEcdf2 <- ggproto("StatEcdf2", StatEcdf, 
    calculate = function(data, scales, n = NULL, minval=NULL, maxval=NULL, ...) { 
    df <- StatEcdf$calculate(data, scales, n, ...) 
    if (!is.null(minval)) { df$x[1] <- minval } 
    if (!is.null(maxval)) { df$x[length(df$x)] <- maxval } 
    df 
    } 
) 

Ora, stat_ecdf2 si comportano allo stesso modo stat_ecdf, ma con un parametro opzionale minval e maxval. Quindi questo farà il trucco:

ggplot(subset(df,target_outcome==1),aes(x = model_rank)) + 
    stat_ecdf2(aes(colour = obs_set), size=1, minval=0, maxval=1) + 
    scale_x_continuous(limits=c(0,1), labels=percent,breaks=seq(0,1,.1)) + 
    xlab("Model Percentile") + ylab("Percent of Target Outcome") + 
    scale_y_continuous(limits=c(0,1), labels=percent) + 
    geom_segment(aes(x=0,y=0,xend=1,yend=1), 
       colour = "gray", linetype="longdash", size=1) + 
    ggtitle("Gain Chart") 

Il grande avvertimento qui è che non so se il modello di estensibilità corrente sarà supportato in futuro; è cambiato più volte in passato, e la modifica all'uso di "ggproto" è recente, come il 15 luglio 2015 recente.

Come un plus, questo mi ha dato la possibilità di scavare davvero in interni di ggplot, che è qualcosa che ho in mente di fare per un po '.

+0

Ho imparato molto da questa risposta - grazie. Molto meglio della mia soluzione alternativa, che ha creato punti dati fittizi (con il rischio di distorcere l'ecdf, almeno su set di dati più piccoli). Questo crea punti fittizi sulla trama stessa. – C8H10N4O2