绘制一个类别变量的一个类别相对于第二个变量的所有类别的份额

Plot the Share of one Category of a Categorical Variable with Respect to all Categories of a Second Variable

我有这样一个数据框:

df <- data.frame(Reason = sample(rep(c("R1", "R2", "R3", "R4"), each = 100)),
                 Answer = sample(rep(c("yes", "no", "no", "no"), 100)))

head(df)

我希望 ggplot 绘制一个条形图,显示每个原因(x 轴)的 "yes" 个答案(y 轴)的份额。

我试过这个:

ggplot(data = df, aes(x = interaction(Reason, Answer))) + 
 geom_bar(aes(y = ..count../sum(..count..)))

这会导致以下结果:

how it looks like

问题是条形总和为 1(总计)。我希望他们在每个原因类别中总结为一个。 (R1.no 和 R1.yes 应该总和为 1,R2.no 和 R2.yes 应该总和为 1,依此类推)。

完成后,我想丢弃所有带有 "no" 答案信息的条形图。所以基本上,我只想要 "yes"-answers 在每个 Reason-category 中的份额。这应该看起来像这样:

how it should look like

这样做我得到了想要的结果:

a <- prop.table(table(df$Reason, df$Answer),1)

df2 <- data.frame(Reason = rownames(as.matrix(a)),
                  share = as.matrix(a)[,2])

ggplot(data = df2, aes(x = reorder(Reason, share), y = share)) + 
  geom_bar(stat = "identity") + 
  ylab("share of yes-answers")

我能否避免这种变通方法并直接从 ggplot 获得所需的结果?这对我来说有一些主要优势。

非常感谢, 安迪

ggplot(df[df$Answer == "yes", ]) + 
  geom_bar(aes(x = Reason, y = sort(..prop..), group = 1))

Yuriy 的解决方案只有在总和为 100 时才有效。我认为你必须以某种方式计算比例,否则你无法预先排序。因此,在第一部分中,我通过添加列 p 来操作数据,如果是,则为 1;如果否,则为 0。

library(dplyr)
library(ggplot2)
set.seed(99)
df <- data.frame(
Reason = sample(rep(c("R1", "R2", "R3", "R4"), each = 100)),
Answer = sample(rep(c("yes", "no", "no", "no"), 100)))

head(df %>% mutate(p=as.numeric(Answer=="yes")),3)
  Reason Answer p
1     R3     no 0
2     R3    yes 1
3     R1     no 0

然后我们用这个数据框作图,y轴就是x轴上每组的平均值,我们可以用stat_summaryfun.y=mean。现在 reorder 在这种情况下效果很好,因为它计算每个类别的平均值并根据该值重新排序:

ggplot(df %>% mutate(p=as.numeric(Answer=="yes")),
aes(x=reorder(Reason,p),y=p)) +
 stat_summary(fun.y="mean",geom="bar",fill="orchid4")

这适用于不同类别的观察数量不同的情况:

set.seed(100)
df <- data.frame(
Reason = rep(c("R1", "R2", "R3", "R4"),times=seq(50,200,length.out=4)),
Answer = sample(c("yes","no"),500,prob=c(0.5,0.5),replace=TRUE)
)
# we expect
sort(tapply(df$Answer=="yes",df$Reason,mean))
R2    R4    R3    R1 
0.460 0.505 0.520 0.540 

ggplot(df %>% mutate(p=as.numeric(Answer=="yes")),
    aes(x=reorder(Reason,p),y=p)) +
     stat_summary(fun.y="mean",geom="bar",fill="orange")