ggplot中如何用百分比替换geom_bar中的计数。

26

我有一个数据框 d:

> head(d,20)
   groupchange Symscore3
1            4         1
2            4         2
3            4         1
4            4         2
5            5         0
6            5         0
7            5         0
8            4         0
9            2         2
10           5         0
11           5         0
12           5         1
13           5         0
14           4         1
15           5         1
16           1         0
17           4         0
18           1         1
19           5         0
20           4         0

我与之密谋的是:

ggplot(d, aes(groupchange, y=..count../sum(..count..),  fill=Symscore3)) +
  geom_bar(position = "dodge") 

这样,每个条形图都代表了它在整个数据中的百分比。

相反,我希望每个条形图代表一个相对百分比;也就是说,在使用groupchange = k时,条形图的总和应为1


1
请考虑更新答案以反映下面更准确和简洁的答案,特别是对于一个明确询问ggplot包的问题,使用***position = "fill"***。否则,当使用position = "fill"时,人们会依赖手动汇总来计算比例,而geom_bar函数本身已经计算了比例。请考虑更新所选答案,以便社区中不再存在低效方法的持续存在。我想引起您和社区的注意。 - HoneyBuddha
4
我不同意@HoneyBuddha的观点,我的做法是否高效取决于具体情况。对于这个简单的用例,你可能是正确的。然而,在处理大型数据集时,根据我的经验,先进行汇总再绘图更加高效。此外,当汇总比直接计算百分比更为复杂时,先进行汇总再绘图会更好。 - Jaap
3个回答

39

如果您的目标是在最少的代码中进行可视化,请在geom_bar()中使用position = "fill"作为参数。

如果您想要组内百分比,在@Jaap的dplyr答案中选择。

以下是使用上述数据集的可重复示例,可复制/粘贴:

library(tidyverse)

d <- data_frame(groupchange = c(4,4,4,4,5,5,5,4,2,5,5,5,5,4,5,1,4,1,5,4),
                Symscore3 = c(1,2,1,2,0,0,0,0,2,0,0,1,0,1,1,0,0,1,1,0))

ggplot(d, aes(x = factor(groupchange), fill = factor(Symscore3))) +
  geom_bar(position="fill")

输入图像描述


2
对于处理小型数据集的人来说,这个选项在代码清晰度/方法效率方面很可能比接受的答案更优。 - HoneyBuddha
这是使用geom_bar()快速在计数和比例之间转换的绝佳方法。 - Megatron

37

首先要对数据进行总结和转换:

library(dplyr)
d2 <- d %>% 
  group_by(groupchange, Symscore3) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count))

然后您可以绘制它:

ggplot(d2, aes(x = factor(groupchange), y = perc*100, fill = factor(Symscore3))) +
  geom_bar(stat="identity", width = 0.7) +
  labs(x = "Groupchange", y = "percent", fill = "Symscore") +
  theme_minimal(base_size = 14)

这将得到:

enter image description here


或者,您可以使用scales包中的percent函数:

brks <- c(0, 0.25, 0.5, 0.75, 1)

ggplot(d2, aes(x = factor(groupchange), y = perc, fill = factor(Symscore3))) +
  geom_bar(stat="identity", width = 0.7) +
  scale_y_continuous(breaks = brks, labels = scales::percent(brks)) +
  labs(x = "Groupchange", y = NULL, fill = "Symscore") +
  theme_minimal(base_size = 14)

显示:

enter image description here


1
鉴于下面给出的更精确的答案,特别是在涉及ggplot包的问题中使用position =“fill”,我认为这个答案可能会导致社区中低效方法的持续存在。我想引起您和整个社区的注意。 - HoneyBuddha
@HoneyBuddha,我确实像OP期望的那样使用了ggplot2。但这并不意味着我不能使用其他工具/包。关于效率问题,请参见我在问题下的评论 - Jaap
1
抱歉,我并不是想暗示您没有使用ggplot2。也许,您可以编辑一下,至少包括position = "fill"选项 - 因为大多数人只看到顶部被接受的答案,可能会错过他们非常简单的解决方案,这对许多新的R用户来说可能会很有帮助。我只是想建议这样一个中间地带。如果您这样做了,请告诉我,这样我就可以删除这些评论。 - HoneyBuddha
3
@HoneyBuddha,我怀疑大多数人只看采纳的答案:我发布了相当多的答案,其中至少有几个赞(甚至有些比采纳的答案更受欢迎)。此外,在编辑中使用“position = 'fill'”选项对我来说感觉像是窃取行为。在SO上,大多数人也认为这是不公平的行为。 - Jaap

8
我们还可以在不显式计算源数据框中的比例的情况下向其添加标签。
library(tidyverse)

d <- data_frame(groupchange = c(4,4,4,4,5,5,5,4,2,5,5,5,5,4,5,1,4,1,5,4),
                Symscore3 = c(1,2,1,2,0,0,0,0,2,0,0,1,0,1,1,0,0,1,1,0)) %>%
  mutate_all(as.character)  # treat the numbers as categories

ggplot(d, aes(x=groupchange, fill=Symscore3)) +
  geom_bar(position="fill") +
  geom_text(
    aes(label=signif(..count.. / tapply(..count.., ..x.., sum)[as.character(..x..)], digits=3)),
    stat="count",
    position=position_fill(vjust=0.5)) +
  labs(y="Proportion")

enter image description here

这个解决方案中的geom_text标签是从这里改编而来的。


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