2012-06-27 4 views
8

Come posso sovrapporre una distribuzione parametrica arbitraria su un istogramma usando ggplot?Come posso sovrapporre una distribuzione parametrica arbitraria su un istogramma usando ggplot?

Ho fatto un tentativo basato su un Quick-R example, ma non capisco da dove proviene il fattore di scala. Questo metodo è ragionevole? Come posso modificarlo per usare ggplot?

Un esempio overplot distribuzioni normali e lognormali utilizzando questo metodo segue:

## 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) 

Questo produce il seguente diagramma: Plot produced by the code above, showing a histogram of word length superimposed with a normal distribution curve and a log-normal distribution curve

Per chiarire, desidero avere conta sulla asse y , piuttosto che una stima della densità.

+0

nota che una distribuzione normale non ha senso perché tutte le parole hanno> 0 lettere, e i valori sono interi discreti; il normale è continuo. –

+0

Concordato - questo è un esempio di giocattolo con un set di dati a portata di mano. E una curva normale è probabilmente inappropriata. – fmark

risposta

11

Dai un'occhiata alla 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

Se si desidera avere conta su l'asse y come nell'esempio, allora avrete bisogno di una funzione che converte la densità alla conta:

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

Bello. Penso che stat_function debba essere nuovo. È un grande miglioramento rispetto al mio approccio precedente, che era quello di creare un frame dati di x, dnorm (x,,) prima. –

+1

@David 'stat_function' è lì da quando riesco a ricordare! :) – joran

+0

Questo è fantastico: è possibile avere conteggi sull'asse y piuttosto che sulla densità come nell'esempio sopra? – fmark