ggplot2: гистограмма с нормальной кривой - PullRequest
28 голосов
/ 06 августа 2011

Я пытался наложить нормальную кривую на мою гистограмму с помощью ggplot 2.

Моя формула:

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

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

Я пробовал несколько вещей:

+ stat_function(fun=dnorm)  

.... ничего не изменилось

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

... дал мне прямую красную линию на оси х.

+ geom_density()  

не работает для меня, потому что я хочу сохранить свои значения частоты на оси Y и не хочу значений плотности.

Есть предложения?

Заранее спасибо за любые советы!

Решение найдено!

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

Ответы [ 4 ]

16 голосов
/ 28 ноября 2012

Думаю, я понял:

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 голосов
/ 01 апреля 2016

На этот вопрос ответили здесь и частично здесь .

Если вы хотите, чтобы ось Y имела счетчики частоты, то нормальную кривую необходимо масштабировать в соответствии с количеством наблюдений и шириной бина.

# 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

EDIT

Или, для более гибкого подхода, который позволяет использовать фасеты и опирается на подход, указанный в здесь , создать отдельный набор данных, содержащий данные для нормальных кривых, и наложить их.

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)
11 голосов
/ 22 октября 2017

Это расширенный комментарий к ответу Дж. Виллимана.Я нашел ответ J очень полезным.Во время игры я обнаружил способ упростить код.Я не говорю, что это лучший способ, но я думал, что упомяну это.

Обратите внимание, что в ответе Дж. Виллимана содержится счетчик по оси y и "хак" для масштабирования соответствующего нормального приближения плотности (который в противном случае охватил бы общую площадь 1 и, следовательно, имел бы гораздо более низкий пик).

Основная мысль этого комментария: более простой синтаксис внутри stat_function, путем передачи необходимых параметров в функцию эстетики, например,

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

Это позволяет избежать необходимости передавать args = на stat_function и, следовательно, более удобно для пользователя.Хорошо, это не очень отличается, но, надеюсь, кто-то найдет это интересным.

# 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

8 голосов
/ 06 августа 2011

Этот код должен делать это:

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

Примечание: я использовал qplot, но вы можете использовать более универсальный ggplot.

...