Ggplot2 - многогрупповая гистограмма с внутригрупповыми пропорциями, а не частотой
У меня есть три когорты студентов, идентифицированных с помощью фактора ExperimentCohort
. Для каждого ученика у меня есть LetterGrade
, также фактор. Я хотел бы построить гистограммную гистограмму LetterGrade
для каждого ExperimentCohort
. Использование
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))
Спасибо.
Ответы
Ответ 1
Неверное решение
Вы можете использовать stat_bin()
и y=..density..
для получения процентов в каждой группе.
ggplot(df, alpha = 0.2,
aes(x = LetterGrade, group = ExperimentCohort, fill = ExperimentCohort))+
stat_bin(aes(y=..density..), position='dodge')
UPDATE - правильное решение
Как указано @rpierce y=..density..
, будут вычисляться значения плотности для каждой группы, а не проценты (они не совпадают).
Чтобы получить правильное решение с процентами, один из способов - рассчитать их перед построением графика. Для этой используемой функции ddply()
из библиотеки plyr
. В каждом 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
и добавлены stat="identity"
внутри geom_bar
.
ggplot(df.new,aes(LetterGrade,prop,fill=ExperimentCohort))+
geom_bar(stat="identity",position='dodge')
![enter image description here]()
Ответ 2
Вы также можете сделать это, создав столбец 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')
Ответ 3
Недавно я попытался это сделать и получил сообщение об ошибке 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')