2015-09-06 149 views
1

我在寻找将中的正态分布拟合添加到分组直方图中最优雅的方式。我知道这个问题之前已经被问过很多次了,但是没有一个建议的选项,比如this onethis one让我觉得非常优雅,至少没有,除非stat_function可以用于每个特定的数据子部分。R:在ggplot2中添加正态拟合到分组直方图

将正态分布拟合叠加到非分组直方图上的一种相对优雅的方法是使用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)) 

enter image description here

我想知道是否虽然这种方法也可以用来添加正态分布适合于分组直方图作为

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

enter image description here

如果有可能定义的任何包我也想知道一个+ stat_distrfit()+ stat_normfit()为ggplot2任何机会(与分组的可能性)? (我真的找不到任何东西,但这似乎是一个普通的任务,所以我只是想知道)

原因我希望代码尽可能短是因为这是一门课程,我想保持尽可能简单...

PS geom_density不适合我的目标,我也想绘制计数/频率而不是密度。我也想让他们在同一个面板上,并避免使用facet_wrap

+0

看看[这篇文章](http://www.stackoverflow。COM /问题/ 25075428#25091231)。 – jlhoward

回答

2

喜欢这个?

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

我想 “优雅” 是在旁观者的眼睛。使用stat_function(...)的问题是args=...列表无法使用aes(...)进行映射,因为注释中的帖子解释了该列表。因此,您必须创建一个辅助数据框架(本例中为gg),该数据具有适合的分布的x值和y值,并使用geom_line(...)

上面的代码在MASS包中使用fitdistr(...)来计算根据正态性假设(如果有意义,您可以使用不同的分布)按性别分组的数据平均值和sd的最大似然估计值。然后通过将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(...)的调用。

+0

非常感谢你 - 这是我一直在寻找的!仍然有点令人惊讶的是,stat_function()不能被映射 - 我真的没有看到任何迟早不应该实现的内在原因......我将尝试将其包装在ggplot2.normhist()中,函数在我的easyGgplot2 fork来保存我的学生一些代码... :-) –