2012-06-27 24 views
8

¿Cómo puedo superponer una distribución paramétrica arbitraria sobre un histograma usando ggplot?¿Cómo puedo superponer una distribución paramétrica arbitraria sobre un histograma usando ggplot?

Hice un intento basado en un Quick-R example, pero no entiendo de dónde viene el factor de escala. ¿Es este método razonable? ¿Cómo puedo modificarlo para usar ggplot?

Un ejemplo overplot las distribuciones normales y lognormal utilizando este método sigue:

## Get a log-normalish data set: the number of characters per word in "Alice in Wonderland" 
alice.raw <- readLines(con = "http://www.gutenberg.org/cache/epub/11/pg11.txt", 
         n = -1L, ok = TRUE, warn = TRUE, 
         encoding = "UTF-8") 

alice.long <- paste(alice.raw, collapse=" ") 
alice.long.noboilerplate <- strsplit(alice.long, split="\\*\\*\\*")[[1]][3] 
alice.words <- strsplit(alice.long.noboilerplate, "[[:space:]]+")[[1]] 
alice.nchar <- nchar(alice.words) 
alice.nchar <- alice.nchar[alice.nchar > 0] 

# Now we want to plot both the histogram and then log-normal probability dist 
require(MASS) 
h <- hist(alice.nchar, breaks=1:50, xlab="Characters in word", main="Count") 
xfit <- seq(1, 50, 0.1) 

# Plot a normal curve 
yfit<-dnorm(xfit,mean=mean(alice.nchar),sd=sd(alice.nchar)) 
yfit <- yfit * diff(h$mids[1:2]) * length(alice.nchar) 
lines(xfit, yfit, col="blue", lwd=2) 

# Now plot a log-normal curve 
params <- fitdistr(alice.nchar, densfun="lognormal") 
yfit <- dlnorm(xfit, meanlog=params$estimate[1], sdlog=params$estimate[1]) 
yfit <- yfit * diff(h$mids[1:2]) * length(alice.nchar) 
lines(xfit, yfit, col="red", lwd=2) 

Esto produce el siguiente diagrama: Plot produced by the code above, showing a histogram of word length superimposed with a normal distribution curve and a log-normal distribution curve

Para aclarar, me gustaría tener recuentos sobre el eje y , en lugar de una estimación de densidad.

+0

nota de que una distribución normal no tiene sentido ya que todas las palabras tienen> 0 letras, y los valores son enteros discretos; lo normal es continuo. –

+0

De acuerdo, este es un ejemplo de juguete con un práctico conjunto de datos. Y una curva normal es probablemente inapropiada. – fmark

Respuesta

11

Tenga una mirada en stat_function()

alice.raw <- readLines(con = "http://www.gutenberg.org/cache/epub/11/pg11.txt", 
         n = -1L, ok = TRUE, warn = TRUE, 
         encoding = "UTF-8") 

alice.long <- paste(alice.raw, collapse=" ") 
alice.long.noboilerplate <- strsplit(alice.long, split="\\*\\*\\*")[[1]][3] 
alice.words <- strsplit(alice.long.noboilerplate, "[[:space:]]+")[[1]] 
alice.nchar <- nchar(alice.words) 
alice.nchar <- alice.nchar[alice.nchar > 0] 
dataset <- data.frame(alice.nchar = alice.nchar) 
library(ggplot2) 
ggplot(dataset, aes(x = alice.nchar)) + geom_histogram(aes(y = ..density..)) + 
    stat_function(fun = dnorm, 
    args = c(
     mean = mean(dataset$alice.nchar), 
     sd = sd(dataset$alice.nchar)), 
    colour = "red") 

enter image description here

Si usted quiere tener cuenta con el eje Y como en el ejemplo, entonces usted tendrá una función que convierte la densidad a los recuentos:

dnorm.count <- function(x, mean = 0, sd = 1, log = FALSE, n = 1, binwidth = 1){ 
    n * binwidth * dnorm(x = x, mean = mean, sd = sd, log = log) 
} 

ggplot(dataset, aes(x = alice.nchar)) + geom_histogram(binwidth=1.6) + 
    stat_function(fun = dnorm.count, 
       args = c(
        mean = mean(dataset$alice.nchar), 
        sd = sd(dataset$alice.nchar), 
        n = nrow(dataset), binwidth=1.6), 
       colour = "red") 

enter image description here

+0

Agradable. Creo que stat_function debe ser nuevo. Es una gran mejora con respecto a mi enfoque anterior, que consistía en crear primero un marco de datos de x, dnorm (x,). –

+1

@David 'stat_function' ha estado ahí por el tiempo que puedo recordar! :) – joran

+0

Esto es genial, ¿es posible tener conteos en el eje y en lugar de densidad como en el ejemplo anterior? – fmark

Cuestiones relacionadas