Применить несколько столбцов к пользовательской функции с помощью dplyr::mutate(поперек())

#r

#r

Вопрос:

df

 a = c("aa", "bb", "cc", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb", "cc", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb","bb") 
b = c("aa", "bb", "cc", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb", "cc", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb","bb") 
c = c("aa", "aa", "aa", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb", "cc", "bb", "bb", "cc","bb", "bb", "cc", "cc", "bb","bb") 
d = c(1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 1)
df = data.frame(a,b,c,d)
  

Имена столбцов:

 cols <- c("a","b","c")
  

Функция:

 rare_label <- function(x){
  freq = prop.table(table(unlist(x)))
  make_rare = names(freq)[freq < 0.20]
  lapply(x,
         function(x) {
           replace(x, x %in% make_rare, "Rare")
         })}
  

Требуется оценить с помощью dplyr::mutate(across()) доли всех значений, объединенных в a, b, c, а затем изменить любую категорию с долей ниже 20% на «Редкую».

Вывод:

      a    b    c
    Rare Rare Rare
    bb   bb   Rare
    cc   cc   Rare
    bb   bb   bb
    bb   bb   bb
    cc   cc   cc
    bb   bb   bb
    .    .    .
    .    .    .
    .    .    .
    
  

Использование приведенного ниже кода выдает ошибку, и я не уверен, почему.

 df %<>%
  mutate(across(where(cols), ~rare_label(.)
  

Ошибка: неожиданный символ в: » мутировать (поперек(где(cols),
~ rare_label(.) Просмотр»

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

1. ваш код в первой строке не работает, один из столбцов короче

2. Исправлено, извините

Ответ №1:

Одним из вариантов может быть:

 df %>%
 mutate(across(all_of(cols), 
               ~ replace(., . %in% names(which(prop.table(table(.)) < 0.20)), "rare")))

      a    b    c d
1  rare rare rare 1
2    bb   bb rare 1
3    cc   cc rare 2
4    bb   bb   bb 2
5    bb   bb   bb 3
6    cc   cc   cc 3
7    bb   bb   bb 1
8    bb   bb   bb 1
9    cc   cc   cc 1
10   cc   cc   cc 1
  

Если вы хотите применить существующую функцию:

 fun <- function(x) replace(x, x %in% names(which(prop.table(table(x)) < 0.20)), "rare")

df %>%
 mutate(across(all_of(cols), fun))
  

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

1. Спасибо, но как я могу выполнить это вычисление с помощью функции?

2. Обновил сообщение.

Ответ №2:

Ваш код работает хорошо, просто измените канал и значения следующим образом:

 #Code
df %>%
    mutate(across(c(a:c), ~rare_label(.))
  

Вывод:

       a    b    c d
1  Rare Rare Rare 1
2    bb   bb Rare 1
3    cc   cc Rare 2
4    bb   bb   bb 2
5    bb   bb   bb 3
6    cc   cc   cc 3
7    bb   bb   bb 1
8    bb   bb   bb 1
9    cc   cc   cc 1
10   cc   cc   cc 1
11   bb   bb   bb 1
12   cc   cc   cc 1
13   bb   bb   bb 2
14   bb   bb   bb 2
15   cc   cc   cc 3
16   bb   bb   bb 3
17   bb   bb   bb 1
18   cc   cc   cc 1
19   cc   cc   cc 1
20   bb   bb   bb 1
21   bb   bb   bb 1
  

Ответ №3:

Ваша функция верна, но вам нужно внести 2 изменения.

  1. Удалите lapply и сохраните последнюю строку как :
 replace(x, x %in% make_rare, "Rare")
  
  1. Удалить where из across , поскольку вы вызываете столбец по их именам.

После внесения этих изменений ваш код должен работать.


Другой вариант — использовать forcats пакет, в котором есть функции для выполнения подобных действий.

 library(dplyr)
library(forcats)

df %>% 
  mutate(across(all_of(cols),fct_lump_min, min = n() * .2, other_level = "rare"))

#      a    b    c d
#1  rare rare rare 1
#2    bb   bb rare 1
#3    cc   cc rare 2
#4    bb   bb   bb 2
#5    bb   bb   bb 3
#6    cc   cc   cc 3
#7    bb   bb   bb 1
#8    bb   bb   bb 1
#9    cc   cc   cc 1
#10   cc   cc   cc 1
#11   bb   bb   bb 1
#12   cc   cc   cc 1
#13   bb   bb   bb 2
#...
  

fct_lump_min изменяет все факторы на «редкие», которые встречаются менее чем в 20% случаев (0,2 * n()). Здесь мы передаем число для n снижения уровней, я не смог найти функцию, которая работает путем передачи самой пропорции, fct_lump_prop делает что-то еще.