web-dev-qa-db-fra.com

ggplot2: histogramme avec courbe normale

J'ai essayé de superposer une courbe normale sur mon histogramme avec ggplot 2.

Ma formule:

data <- read.csv (path...)

ggplot(data, aes(V2)) + 
  geom_histogram(alpha=0.3, fill='white', colour='black', binwidth=.04)

J'ai essayé plusieurs choses:

+ stat_function(fun=dnorm)  

.... n'a rien changé

+ stat_density(geom = "line", colour = "red")

... m'a donné une ligne rouge droite sur l'axe des x.

+ geom_density()  

ne fonctionne pas pour moi parce que je veux garder mes valeurs de fréquence sur l'axe y et ne veux pas de valeurs de densité.

Aucune suggestion?

Merci d'avance pour des conseils!

Solution trouvée!

+geom_density(aes(y=0.045*..count..), colour="black", adjust=4)

32
Bloomy

Cela a été répondu ici et partiellement ici .

Si vous souhaitez que l'axe des y ait des nombres de fréquences, la courbe normale doit être mise à l'échelle en fonction du nombre d'observations et de la largeur de bande.

# Simulate some data. Individuals' heights in cm.
n        <- 1000
mean     <- 165
sd       <- 6.6
binwidth <- 2
height <- rnorm(n, mean, sd)


qplot(height, geom = "histogram", breaks = seq(130, 200, binwidth), 
      colour = I("black"), fill = I("white"),
      xlab = "Height (cm)", ylab = "Count") +
  # Create normal curve, adjusting for number of observations and binwidth
  stat_function( 
    fun = function(x, mean, sd, n, bw){ 
      dnorm(x = x, mean = mean, sd = sd) * n * bw
    }, 
    args = c(mean = mean, sd = sd, n = n, bw = binwidth))

Histogram with normal curve

ÉDITER

Ou, pour une approche plus flexible qui permet l'utilisation des facettes et s'appuie sur une approche répertoriée ici , créez un ensemble de données distinct contenant les données des courbes normales et superposez-les.

library(plyr)

dd <- data.frame(
  predicted = rnorm(720, mean = 2, sd = 2),
  state = rep(c("A", "B", "C"), each = 240)
) 

binwidth <- 0.5

grid <- with(dd, seq(min(predicted), max(predicted), length = 100))
normaldens <- ddply(dd, "state", function(df) {
  data.frame( 
    predicted = grid,
    normal_curve = dnorm(grid, mean(df$predicted), sd(df$predicted)) * length(df$predicted) * binwidth
  )
})

ggplot(dd, aes(predicted))  + 
  geom_histogram(breaks = seq(-3,10, binwidth), colour = "black", fill = "white") + 
  geom_line(aes(y = normal_curve), data = normaldens, colour = "red") +
  facet_wrap(~ state)
17
JWilliman

Je pense que je l'ai:

set.seed(1)
df <- data.frame(PF = 10*rnorm(1000))
ggplot(df, aes(x = PF)) + 
    geom_histogram(aes(y =..density..),
                   breaks = seq(-50, 50, by = 10), 
                   colour = "black", 
                   fill = "white") +
stat_function(fun = dnorm, args = list(mean = mean(df$PF), sd = sd(df$PF)))

enter image description here

16

Il s'agit d'un commentaire étendu sur la réponse de JWilliman. J'ai trouvé la réponse de J très utile. En jouant, j'ai découvert un moyen de simplifier le code. Je ne dis pas que c'est une meilleure façon, mais j'ai pensé que je le mentionnerais.

Notez que la réponse de JWilliman fournit le compte sur l'axe des y et un "hack" pour mettre à l'échelle l'approximation normale de densité correspondante (qui autrement couvrirait une zone totale de 1 et aurait donc un pic beaucoup plus bas).

Point principal de ce commentaire: syntaxe plus simple à l'intérieur de stat_function, En passant les paramètres nécessaires à la fonction esthétique, par ex.

aes(x = x, mean = 0, sd = 1, binwidth = 0.3, n = 1000)

Cela évite d'avoir à passer args = À stat_function Et est donc plus convivial. D'accord, ce n'est pas très différent, mais j'espère que quelqu'un le trouvera intéressant.

# parameters that will be passed to ``stat_function``
n = 1000
mean = 0
sd = 1
binwidth = 0.3 # passed to geom_histogram and stat_function
set.seed(1)
df <- data.frame(x = rnorm(n, mean, sd))

ggplot(df, aes(x = x, mean = mean, sd = sd, binwidth = binwidth, n = n)) +
    theme_bw() +
    geom_histogram(binwidth = binwidth, 
        colour = "white", fill = "cornflowerblue", size = 0.1) +
stat_function(fun = function(x) dnorm(x, mean = mean, sd = sd) * n * binwidth,
    color = "darkred", size = 1)

enter image description here

13
PatrickT

Ce code devrait le faire:

set.seed(1)
z <- rnorm(1000)

qplot(z, geom = "blank") + 
geom_histogram(aes(y = ..density..)) + 
stat_density(geom = "line", aes(colour = "bla")) + 
stat_function(fun = dnorm, aes(x = z, colour = "blabla")) + 
scale_colour_manual(name = "", values = c("red", "green"), 
                               breaks = c("bla", "blabla"), 
                               labels = c("kernel_est", "norm_curv")) + 
theme(legend.position = "bottom", legend.direction = "horizontal")

enter image description here

Remarque: j'ai utilisé qplot mais vous pouvez utiliser le ggplot plus polyvalent.

8
dickoa