Ggplot2 - многогрупповая гистограмма с внутригрупповыми пропорциями, а не частотой - программирование

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

Спасибо.

4b9b3361

Ответ 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')