R:将正常拟合添加到 ggplot2 中的分组直方图

R: add normal fits to grouped histograms in ggplot2

我正在寻找在 ggplot2 的分组直方图中叠加正态分布拟合的最优雅的方法。我知道这个问题之前已经被问过很多次,但是 none 的建议选项,比如 this one or this one 让我觉得非常优雅,至少不会,除非 stat_function 可以在每个选项上工作数据的特定部分。

将正态分布拟合叠加到我确实遇到的非分组直方图的一种相对优雅的方法是使用 geom_smoothmethod="nls"(除此之外它不是自我-起始函数并且必须指定起始值):

library(ggplot2)
myhist = data.frame(size = 10:27, counts = c(1L, 3L, 5L, 6L, 9L, 14L, 13L, 23L, 31L, 40L, 42L, 22L, 14L, 7L, 4L, 2L, 2L, 1L) )
ggplot(data=myhist, aes(x=size, y=counts)) + geom_point() + 
     geom_smooth(method="nls", formula = y ~ N * dnorm(x, m, s), se=F, 
                 start=list(m=20, s=5, N=300)) 

我想知道这种方法是否也可以用于将正态分布拟合添加到分组直方图中,如

library(devtools)
install_github("tomwenseleers/easyGgplot2",type="source")
library("easyGgplot2") # load weight data
ggplot(weight,aes(x = weight)) + 
+     geom_histogram(aes(y = ..count.., colour=sex, fill=sex),alpha=0.5,position="identity")

我还想知道是否有任何包可以为 ggplot2 定义 + stat_distrfit()+ stat_normfit()(有可能进行分组)? (我真的找不到任何东西,但这似乎是一个很常见的任务,所以我只是想知道)

我希望代码尽可能短的原因是这是一门课程,我想让事情尽可能简单...

PS geom_density 不符合我的目标,我还想绘制 counts/frequencies 而不是密度。我也希望将它们放在同一个面板中,并避免使用 facet_wrap

像这样?

## simulate your dataset - could not get easyGplot2 to load....
set.seed(1)     # for reproducible example
weight <- data.frame(sex=c("Female","Male"), weight=rnorm(1000,mean=c(65,67),sd=1))

library(ggplot2)
library(MASS)       # for fitdistr(...)
get.params <- function(z) with(fitdistr(z,"normal"),estimate[1:2])
df <- aggregate(weight~sex, weight, get.params)
df <- data.frame(sex=df[,1],df[,2])
x  <- with(weight, seq(min(weight),max(weight),len=100))
gg <- data.frame(weight=rep(x,nrow(df)),df)
gg$y <- with(gg,dnorm(x,mean,sd))
gg$y <- gg$y * aggregate(weight~sex, weight,length)$weight * diff(range(weight$weight))/30

ggplot(weight,aes(x = weight, colour=sex)) + 
  geom_histogram(aes(y = ..count.., fill=sex), alpha=0.5,position="identity") +
  geom_line(data=gg, aes(y=y))  

我想 "elegant" 是仁者见仁智者见智吧。使用 stat_function(...) 的问题是无法使用 aes(...) 映射 args=... 列表,正如评论中的 post 所解释的那样。因此,您必须创建一个辅助 data.frame(本例中为 gg),它具有拟合分布的 x 和 y 值,并使用 geom_line(...).

上面的代码使用 MASS 包中的 fitdistr(...) 来计算数据均值和标准差的最大似然估计值,根据正态性假设按性别分组(您可以使用如果有意义的话,不同的分布)。然后,它通过将 weight 中的范围划分为 100 个增量来创建 x 轴,并计算 dnorm(x,...) 以获得适当的均值和 sd。由于结果是密度,我们必须调整它使用:

gg$y <- gg$y * aggregate(weight~sex, weight,length)$weight * diff(range(weight$weight))/30

因为您想将其映射到计数数据。请注意,这假设您使用 geom_histogram 中的默认分箱(它将 x 中的范围划分为 30 个相等的增量)。最后,我们使用 gg 作为层特定数据集添加对 geom_line(...) 的调用。