Сохранение порядка факторов после сбора и суммирования шагов в tidyverse

У меня более сотни переменных, для которых я пытаюсь вычислить частоту и процент. Как я могу сохранить факторный порядок значений каждой переменной в выходных данных? Обратите внимание, что указывать порядок для каждой переменной вне набора данных нецелесообразно, поскольку у меня более 100 переменных.

Пример данных:

df <- data.frame(gender=factor(c("male", "female", "male", NA), levels=c("male", "female")),
                 disease=factor(c("yes","yes","no", NA), levels=c("yes", "no")))
df
  gender disease
1   male     yes
2 female     yes
3   male      no
4   <NA>    <NA>

Пытаться:

df %>% gather(key, value, factor_key = T) %>%
  group_by(key, value) %>% 
  summarise(n=n()) %>%
  ungroup() %>%
  group_by(key) %>%
  mutate(percent=n/sum(n))

Выход:

# A tibble: 6 x 4
# Groups:   key [2]
  key     value      n percent
  <fct>   <chr>  <int>   <dbl>
1 gender  female     1    0.25
2 gender  male       2    0.5 
3 gender  NA         1    0.25
4 disease no         1    0.25
5 disease yes        2    0.5 
6 disease NA         1    0.25

Желаемый результат: пол как мужской, женский и болезнь как да, нет.


person EML    schedule 16.10.2020    source источник
comment
Я ищу потенциальный способ избежать повторного определения уровней отчасти потому, что со многими переменными некоторые уровни могут не использоваться; Я не могу предвидеть порядок значений при изменении данных.   -  person EML    schedule 16.10.2020


Ответы (1)


Обновление: если вы используете pivot_longer (новый сбор), он сохраняет уровни факторов! Вы также можете точно настроить типы столбцов с помощью аргументов names_transform и values_transform в pivot_longer.

library(tidyverse)
df <- data.frame(gender=factor(c("male", "female", "male", NA), levels=c("male", "female")),
                 disease=factor(c("yes","yes","no", NA), levels=c("yes", "no")))

df %>% 
  pivot_longer(everything()) %>%
  group_by(name, value) %>% 
  summarise(n=n(), .groups = "drop_last") %>%
  mutate(percent=n/sum(n))
#> # A tibble: 6 x 4
#> # Groups:   name [2]
#>   name    value      n percent
#>   <chr>   <fct>  <int>   <dbl>
#> 1 disease yes        2    0.5 
#> 2 disease no         1    0.25
#> 3 disease <NA>       1    0.25
#> 4 gender  male       2    0.5 
#> 5 gender  female     1    0.25
#> 6 gender  <NA>       1    0.25

Создано 16.10.2020 пакетом REPEX (v0.3.0)


Поскольку при сборке коэффициент для переменной значения снижается, а при суммировании также оказывается, что удаляются атрибуты фрейма данных, вам придется добавить их повторно. Вы можете повторно добавить их в полуавтоматическом режиме, считывая и комбинируя уровни факторов следующим образом:

library(tidyverse)
df <- data.frame(gender=factor(c("male", "female", "male", NA), levels=c("male", "female")),
                 disease=factor(c("yes","yes","no", NA), levels=c("yes", "no")))

df %>% 
  gather(key, value, factor_key = T) %>%
  group_by(key, value) %>% 
  summarise(n=n()) %>%
  ungroup() %>%
  group_by(key) %>%
  mutate(percent=n/sum(n),
         value = factor(value, levels = df %>% map(levels) %>% unlist())) %>%
  arrange(key, value)
#> Warning: attributes are not identical across measure variables;
#> they will be dropped
#> `summarise()` regrouping output by 'key' (override with `.groups` argument)
#> # A tibble: 6 x 4
#> # Groups:   key [2]
#>   key     value      n percent
#>   <fct>   <fct>  <int>   <dbl>
#> 1 gender  male       2    0.5 
#> 2 gender  female     1    0.25
#> 3 gender  <NA>       1    0.25
#> 4 disease yes        2    0.5 
#> 5 disease no         1    0.25
#> 6 disease <NA>       1    0.25

Создано 16.10.2020 пакетом REPEX (v0.3.0)

person Arthur Yip    schedule 16.10.2020
comment
Какие-нибудь советы по переносу NA в качестве первого значения? Я попробовал level = c (NA, мужской, женский), но это не сработало. - person EML; 20.10.2020
comment
Для решения 1 попробуйте c (NA, мужской, женский) или c (NA_character_, мужской, женский) Для решения 2 попробуйте factor (value, levels = c (NA, df% ›% map (levels)%›% unlist ( ))) - person Arthur Yip; 20.10.2020