ggplot2 - 多组直方图,显示组内比例而不是频率

26

我有三组学生,由一个名为ExperimentCohort的因素进行区分。对于每个学生,我都有一个名为LetterGrade的因素。我想为每个ExperimentCohort绘制一个类似直方图的条形图,其中包括LetterGrade的数据。使用以下代码:

ggplot(df, alpha = 0.2, 
       aes(x = LetterGrade, group = ExperimentCohort, fill = ExperimentCohort))                                                                                                                                                       
  + geom_bar(position = "dodge")

这个方案已经很接近了,但是三个 ExperimentCohorts 的学生人数不一样。为了更公平地比较它们,我希望将 y 轴设置为每个等级字母的组内比例。到目前为止,除了在绘图之前计算这个比例并将其放入单独的数据框中之外,我没有找到其他方法来实现这一点。

在 SO 和其他地方寻求类似问题的解决方案时,每个解决方案都涉及 aes(y = ..count../sum(..count..)),但是 sum(..count..) 是在整个数据框中执行而不是在每个队列中执行。有人有建议吗?以下是创建示例数据框的代码:

df <- data.frame(ID = 1:60, 
        LetterGrade = sample(c("A", "B", "C", "D", "E", "F"), 60, replace = T),
        ExperimentCohort = sample(c("One", "Two", "Three"), 60, replace = T))

感谢您的选择。

该标题涉及直方图,而不是条形图。 - Julien
3个回答

25

错误的解决方案

您可以使用stat_bin()y=..density..来获取每组中的百分比。

ggplot(df, alpha = 0.2,
      aes(x = LetterGrade, group = ExperimentCohort, fill = ExperimentCohort))+
      stat_bin(aes(y=..density..), position='dodge')

更新 - 正确解决方案

正如@rpierce所指出的,y=..density..将为每个组计算密度值而不是百分比(它们不同)。

要获得正确的百分比解决方案,一种方法是在绘图之前计算它们。使用库plyr中的函数ddply()进行计算。在每个ExperimentCohort中,使用函数prop.table()table()计算比例,并将其保存为prop。使用names()table()获取了LetterGrade

df.new<-ddply(df,.(ExperimentCohort),summarise,
              prop=prop.table(table(LetterGrade)),
              LetterGrade=names(table(LetterGrade)))

 head(df.new)
  ExperimentCohort       prop LetterGrade
1              One 0.21739130           A
2              One 0.08695652           B
3              One 0.13043478           C
4              One 0.13043478           D
5              One 0.30434783           E
6              One 0.13043478           F

现在使用这个新的数据框进行绘图。由于比例已经计算好了,所以将它们作为y值提供,并在geom_bar内部添加stat="identity"

ggplot(df.new,aes(LetterGrade,prop,fill=ExperimentCohort))+
  geom_bar(stat="identity",position='dodge')

在这里输入图像描述


做得好。非常感谢……不知道为什么我没能在其他地方找到这个答案。你知道 ..count.. 有什么特殊之处,会表现出这种行为,而 ..density.. 却没有吗?或者这是 geom_barstat_bin 之间差异的普遍现象吗? - Claire Sannier
stat_bin函数是分别应用于每个组的。 - Didzis Elferts
除此答案不太正确:http://stats.stackexchange.com/questions/4220/a-probability-distribution-value-exceeding-1-is-ok。请参见:https://dev59.com/0HTYa4cB1Zd3GeqPvHgN以获得正确的解决方案。 - russellpierce
1
@rpierce 修正了我的答案。 - Didzis Elferts
9
我最近尝试过这个方法,回家的路走得差不多了,但需要在prop=prop.table(table(LetterGrade))中加入as.numeric函数,变成prop=as.numeric(prop.table(table(LetterGrade))) - tchakravarty
这不是直方图,它是一种条形图。 - Julien

8
你也可以通过创建一个 weight 列来为每个组加总到1,来实现这一点。
ggplot(df %>%
         group_by(ExperimentCohort) %>%
         mutate(weight = 1 / n()),
       aes(x = LetterGrade, fill = ExperimentCohort)) +
  geom_histogram(aes(weight = weight), stat = 'count', position = 'dodge')

1
对我来说,stat="count" 的代码在使用 stat_count 时产生了一些问题。移除它就可以解决。 - wake_wake
似乎无法按组显示百分比。 - Julien

0

最近我尝试了这个,但是调用ddply时出现了错误:Column prop must be length 1 (a summary value), not 6。花了一些时间研究ddply,但是无法完全解决问题,所以我提供了一个替代方案(请注意,这仍然使用plyr):

df.new <- df2 %>% 
    group_by(ExperimentCohort,LetterGrade) %>% 
    summarise (n = n()) %>%
    mutate(freq = n / sum(n))

然后你可以像 @didzis-elferts 提到的那样绘制它:

ggplot(df.new,aes(LetterGrade,freq,fill=ExperimentCohort))+
    geom_bar(stat="identity",position='dodge')

你能解释一下 mutate 步骤吗?为什么 sum(n) 只在 experimentcohort 内部?我本来以为 sum(n) 是针对整个数据框的 - 看起来好像有点神奇! - seanv507
1
如果我们想要在整个数据框上计算 sum(n),我们需要在 mutate 调用之前在管道中调用 ungroup()。请注意,您可以使用 grouping(df.new) 检查分组情况,并且 summarise 调用将“取消分组”最后一个分组变量。 - mploenzke
例如,向数据框添加一列:df <- data.frame(ID = 1:60,LetterGrade = sample(c("A", "B", "C", "D", "E", "F"), 60, replace = T),ExperimentCohort = sample(c("One", "Two", "Three"), 60, replace = T), test = sample(c("A", "B", "C", "D", "E", "F"), 60, replace = T))然后将以下输出进行比较:df %>% group_by(ExperimentCohort,LetterGrade,test) %>% summarise (n = n()) %>% group_vars()与:df %>% group_by(ExperimentCohort,LetterGrade,test) %>% group_vars() - mploenzke
这就是为什么 mutate(freq = n / sum(n)) 计算的总和现在只涵盖了 ExperimentCohort 组,而不再涵盖 LetterGrade 组。希望这能够帮助你理解! - mploenzke
问题是关于直方图,而不是条形图。 - Julien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接