Ombreggiatura di un grafico della densità del kernel tra due punti.


94

Uso spesso i grafici della densità del kernel per illustrare le distribuzioni. Questi sono facili e veloci da creare in R in questo modo:

set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)
plot(dens)
#or in one line like this: plot(density(rnorm(100)^2))

Il che mi dà questo bel piccolo PDF:

inserisci qui la descrizione dell'immagine

Vorrei ombreggiare l'area sotto il PDF dal 75 ° al 95 ° percentile. È facile calcolare i punti utilizzando ilquantile funzione:

q75 <- quantile(draws, .75)
q95 <- quantile(draws, .95)

Ma come ombreggiare l'area tra q75eq95 ?


Potete fornire un esempio di ombreggiatura dell'esterno della vostra gamma rispetto alla parte interna della vostra gamma? Grazie.
Milktrader

Risposte:


75

Con la polygon()funzione, vedere la sua pagina di aiuto e credo che anche qui abbiamo avuto domande simili.

È necessario trovare l'indice dei valori del quantile per ottenere le (x,y)coppie effettive .

Modifica: ecco qui:

x1 <- min(which(dens$x >= q75))  
x2 <- max(which(dens$x <  q95))
with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))

Output (aggiunto da JDL)

inserisci qui la descrizione dell'immagine


3
Non l'avrei mai fatto funzionare se non avessi fornito la struttura. Grazie!
JD Long

2
È una di quelle cose ... che sono arrivate puntualmente demo(graphics)da prima dell'alba, quindi ogni tanto ci si imbatte. Stessa idea per l'ombreggiatura della regressione NBER ecc.
Dirk Eddelbuettel

1
ohhhh. SAPEVO di averlo visto da qualche parte ma non potevo estrarlo dal mio indice mentale dove l'avevo visto. Sono contento che il tuo indice mentale sia migliore del mio.
JD Long

70

Un'altra soluzione:

dd <- with(dens,data.frame(x,y))

library(ggplot2)

qplot(x,y,data=dd,geom="line")+
  geom_ribbon(data=subset(dd,x>q75 & x<q95),aes(ymax=y),ymin=0,
              fill="red",colour=NA,alpha=0.5)

Risultato:

testo alternativo


21

Una soluzione ampliata:

Se si desidera ombreggiare entrambe le code (copia e incolla del codice di Dirk) e utilizzare valori x noti:

set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)
plot(dens)

q2     <- 2
q65    <- 6.5
qn08   <- -0.8
qn02   <- -0.2

x1 <- min(which(dens$x >= q2))  
x2 <- max(which(dens$x <  q65))
x3 <- min(which(dens$x >= qn08))  
x4 <- max(which(dens$x <  qn02))

with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))
with(dens, polygon(x=c(x[c(x3,x3:x4,x4)]), y= c(0, y[x3:x4], 0), col="gray"))

Risultato:

Poliestere a 2 code


Ho il file png e l'ho ospitato su freeimagehosting, e potrebbe non essere caricato perché ... non sono sicuro.
Milktrader

File molto sfocato. Puoi ricrearlo e caricarlo direttamente qui, quindi ha un proprio servizio di server per questo?
Dirk Eddelbuettel

Mi dispiace, ma non riesco a vedere come caricarlo direttamente su SO.
Milktrader

18

Questa domanda ha bisogno di una latticerisposta. Eccone uno molto semplice, semplicemente adattando il metodo impiegato da Dirk e altri:

#Set up the data
set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)

#Put in a simple data frame   
d <- data.frame(x = dens$x, y = dens$y)

#Define a custom panel function;
# Options like color don't need to be hard coded    
shadePanel <- function(x,y,shadeLims){
    panel.lines(x,y)
    m1 <- min(which(x >= shadeLims[1]))
    m2 <- max(which(x <= shadeLims[2]))
    tmp <- data.frame(x1 = x[c(m1,m1:m2,m2)], y1 = c(0,y[m1:m2],0))
    panel.polygon(tmp$x1,tmp$y1,col = "blue")
}

#Plot
xyplot(y~x,data = d, panel = shadePanel, shadeLims = c(1,3))

inserisci qui la descrizione dell'immagine


3

Ecco un'altra ggplot2variante basata su una funzione che approssima la densità del kernel ai valori dei dati originali:

approxdens <- function(x) {
    dens <- density(x)
    f <- with(dens, approxfun(x, y))
    f(x)
}

L'utilizzo dei dati originali (piuttosto che produrre un nuovo frame di dati con i valori xey della stima della densità) ha il vantaggio di lavorare anche in grafici sfaccettati in cui i valori quantile dipendono dalla variabile in base alla quale i dati vengono raggruppati:

Codice utilizzato

library(tidyverse)
library(RColorBrewer)

# dummy data
set.seed(1)
n <- 1e2
dt <- tibble(value = rnorm(n)^2)

# function that approximates the density at the provided values
approxdens <- function(x) {
    dens <- density(x)
    f <- with(dens, approxfun(x, y))
    f(x)
}

probs <- c(0.75, 0.95)

dt <- dt %>%
    mutate(dy = approxdens(value),                         # calculate density
           p = percent_rank(value),                        # percentile rank 
           pcat = as.factor(cut(p, breaks = probs,         # percentile category based on probs
                                include.lowest = TRUE)))

ggplot(dt, aes(value, dy)) +
    geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
    geom_line() +
    scale_fill_brewer(guide = "none") +
    theme_bw()



# dummy data with 2 groups
dt2 <- tibble(category = c(rep("A", n), rep("B", n)),
              value = c(rnorm(n)^2, rnorm(n, mean = 2)))

dt2 <- dt2 %>%
    group_by(category) %>% 
    mutate(dy = approxdens(value),    
           p = percent_rank(value),
           pcat = as.factor(cut(p, breaks = probs,
                                include.lowest = TRUE)))

# faceted plot
ggplot(dt2, aes(value, dy)) +
    geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
    geom_line() +
    facet_wrap(~ category, nrow = 2, scales = "fixed") +
    scale_fill_brewer(guide = "none") +
    theme_bw()

Creato il 13/07/2018 dal pacchetto reprex (v0.2.0).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.