Мутировать (через (all_of())) Ошибка пользовательской функции

#r

#r

Вопрос:

df1:

 library(caret)
library(magrittr)
library(dplyr)

#Vectors
a = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
b = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
c = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
d = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
e = c(1, 0, 1, 0, 0, 0, 1, 1, 1, 1)

#df1
df1 = data.frame(a,b,c,d,e)
  

Вектор имен столбцов, пропорции переменных в столбцах, пользовательская функция для кодирования значений <30% как «редких»

 #Col Name Vector
cols <- c("a", "b", "c")

#Col Proportions
freq = prop.table(table(unlist(df1[cols])))
make_rare = names(freq)[freq< 0.3]

#Functions
#Rare label
rare_label <- function(x,cv){
  replace(x, x %in% cv, "Rare")
}
  

Канал Magrittr:

 #Pipeline
df1 <- df1 %>%
  #Rare Label Encoding
  mutate(d = rare_label(d,make_rare)) %>%
  mutate(across(all_of(cols), rare_label(cv=make_rare)))
  

Мой вопрос в том, почему последний mutate(across(all_of())) не работает, но приведенный выше mutate использует ту же функцию?

Я хочу сохранить код в этом формате (пользовательская функция), поскольку я хочу создать «библиотеку» функций, которые я могу вызывать для этого типа работы.

Вывод:

 a    b    c    d    e
aa   aa   aa   aa   1
bb   bb   bb   bb   0
Rare Rare Rare Rare 1
aa   aa   aa   aa   0
aa   aa   aa   aa   0
aa   aa   aa   aa   0
bb   bb   bb   bb   1
Rare Rare Rare Rare 1
bb   bb   bb   bb   1
bb   bb   bb   bb   1
  

Ответ №1:

rare_label требуется два аргумента, x и cv . При across вызове вы не указываете x аргумент. Вы можете использовать свою функцию, across например, таким образом:

 library(dplyr)

#Vectors
a = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
b = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
c = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
d = c("aa", "bb", "cc", "aa", "aa", "aa", "bb", "cc", "bb", "bb") 
e = c(1, 0, 1, 0, 0, 0, 1, 1, 1, 1)

#df1
df1 = data.frame(a,b,c,d,e)

#Col Name Vector
cols <- c("a", "b", "c")

#Col Proportions
freq = prop.table(table(unlist(df1[cols])))
make_rare = names(freq)[freq< 0.3]

#Functions
#Rare label
rare_label <- function(x,cv){
  replace(x, x %in% cv, "Rare")
}

#Pipeline
df1 <- df1 %>%
  #Rare Label Encoding
  mutate(d = rare_label(d,make_rare)) %>%
  mutate(across(all_of(cols), ~rare_label(x = .x, cv=make_rare)))
 df1
      a    b    c    d e
1    aa   aa   aa   aa 1
2    bb   bb   bb   bb 0
3  Rare Rare Rare Rare 1
4    aa   aa   aa   aa 0
5    aa   aa   aa   aa 0
6    aa   aa   aa   aa 0
7    bb   bb   bb   bb 1
8  Rare Rare Rare Rare 1
9    bb   bb   bb   bb 1
10   bb   bb   bb   bb 1
  

В across , у вас есть 3 возможности, как использовать функцию:

  • если первый аргумент функции — это то, куда входит ваш входной вектор (и возможные другие аргументы задавать не нужно), вы можете просто использовать имя функции, например data %>% mutate(across(everything(), log))
  • если первый аргумент функции — это то, куда входит ваш входной вектор, и вы хотите указать другие аргументы, вы можете просто перечислить эти аргументы после имени функции, например data %>% mutate(across(everything(), log, base = 10))
  • вы можете использовать purrr формулы стиля для создания анонимных функций; вы можете прочитать ~log(.x) как «применить log к .x где .x аргумент, предоставленный анонимной функции. Оно равно function(.x) {log(.x)} , .x выбрано в качестве имени, чтобы не возникало конфликтов имен, вы также можете использовать другое имя переменной. Здесь с приложением in mutate .x передается столбец log , например, in data %>% mutate(across(column_1, ~log(.x))) .x — это значения / вектор column_1 . Если вы выбираете несколько столбцов в across , log применяется по столбцам, то .x же самое относится и к значениям соответствующего столбца, к которому log применяется, например data %>% mutate(across(everything(), ~log(.x)))

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

1. Не могли бы вы объяснить или предоставить мне статью, показывающую, что делает ~rare_label(x = .x («~» и «.x»)?

2. Помогают ли мои объяснения? Я чувствую, что сделал это слишком сложным.