Facet_wrap: масштабирование Y от 0 до 1 на основе отображаемой переменной

#r #ggplot2 #facet-wrap

#r #ggplot2 #обтекание фасета

Вопрос:

Есть ли способ масштабировать ось y при обтекании фасетами от 0 до 1 на основе отображаемой переменной, в моем случае (см. Ниже) пола? Как если бы ..count.. / max(..count..) данные были сгруппированы по gender переменной. Любые идеи будут высоко оценены.

Ниже приведена моя текущая попытка

 ex[c("var1","var2", "gender")] %>%
  gather(-gender, key="var", value = "value") %>% 
  ggplot(aes(value, fill = gender))    geom_histogram(aes(y=..count.. / max(..count..)), stat="count")   
  facet_wrap(~var   gender, scales = "free_x", ncol= 2)   
  ylab("% in each group") 
  

В результате
введите описание изображения здесь

Образец данных:

 structure(list(row = 1:100, var1 = c(" <25", " <25", " 25-50", 
" 25-50", " 50-75", " <25", " 25-50", " 25-50", " 25-50", " 25-50", 
" 50-75", " 25-50", " 25-50", " 25-50", " <25", " 25-50", " 25-50", 
" 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", 
">75", " 25-50", " 25-50", " <25", " <25", " 25-50", " 25-50", 
" 25-50", " 50-75", " 50-75", " 25-50", " 25-50", " 50-75", " 25-50", 
" 25-50", " <25", " 25-50", " 25-50", " 25-50", " 25-50", " <25", 
" 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", 
" 25-50", " 50-75", " 50-75", " <25", " 25-50", " <25", " 50-75", 
" <25", " <25", " <25", " 25-50", " <25", " <25", " 25-50", " 50-75", 
" 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " <25", " 25-50", 
" <25", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " <25", 
" 50-75", " 25-50", " 25-50", " 25-50", " 25-50", " 25-50", " 50-75", 
" 25-50", " <25", " 25-50", " 25-50", " <25", " 25-50", " <25", 
" <25", " 25-50", " 25-50", " <25", " <25"), var2 = c(0L, 0L, 
0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 
0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 
1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L), gender = c("M", "M", "M", "M", "M", "M", "M", "F", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "F", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "F", "M", "M", "M", "M", "M", "M", "M", "M", 
"F", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M"
)), class = "data.frame", row.names = c(NA, -100L))
  

Комментарии:

1. Не могли бы вы, пожалуйста, уточнить, что должно составлять 100%, может быть, вы сможете дать ожидаемый результат?

Ответ №1:

Насколько мне известно, не существует готового решения, которое указывало бы facet_wrap выполнять нормализацию, которую вы пытаетесь достичь. Вместо этого вам придется делать это вручную.

Для достижения этого существует (по крайней мере) два подхода:

  1. Простым подходом было бы предварительное вычисление (нормализованных) значений и использование geom_col
  2. Более сложным подходом было бы использовать, например, tapply для вычисления максимального количества с помощью gender . Для этого подхода я бы рекомендовал переключиться на geom_bar вместо использования geom_histogram .

Оба подхода показаны ниже:

 library(ggplot2)
library(tidyr)
library(dplyr)

ex[c("var1","var2", "gender")] %>%
  gather(-gender, key="var", value = "value") %>% 
  count(gender, var, value) %>% 
  group_by(gender) %>% 
  mutate(pct = n / max(n)) %>% 
  ggplot(aes(value, pct, fill = gender))    
  geom_col()  
  facet_wrap(~var   gender, scales = "free_x", ncol= 2)   
  ylab("% in each group") 
  

 ex[c("var1","var2", "gender")] %>%
  gather(-gender, key="var", value = "value") %>% 
  ggplot(aes(value, fill = gender))    
  geom_bar(aes(y = ..count.. / tapply(..count.., ..fill.., function(x) max(x))[..fill..]), stat="count")   
  facet_wrap(~var   gender, scales = "free_x", ncol= 2)   
  ylab("% in each group")
  

Комментарии:

1. Есть ли какой-либо способ, чтобы столбцы внутри каждой категории (для каждой переменной) суммировались до 1? Текущее решение, которое у меня есть, использует geom_bar(aes(y = ..count.. / tapply(..count.., ..fill.., function(x) sum(x))[..fill..]), stat="count") для каждой переменной отдельно ylim (0,1), а затем использует grid.arrange, но я считаю, что должно быть более плавное решение? Большое спасибо

2. Привет @Randomcloud. Да. grid.arrange не требуется. В целом я бы предположил, что использовать мой первый подход с использованием предварительно вычисленных значений проще в обращении. Там вы можете просто сгруппировать по переменной и полу. Для второго подхода вам нужно сделать ggplot(aes(value, fill = gender, group = interaction(var, gender))) geom_bar(aes(y = ..count.. / tapply(..count.., ..group.., function(x) sum(x))[..group..]), stat="count") . Здесь мы сначала сопоставляем interaction(var, gender) на group , которые затем могут быть использованы в geom_bar или tapply для выполнения вычислений по переменной / полу …

3. … в любом случае вам все равно понадобится ylim (0, 1) для установки ограничений.