Функция lapply с аргументами для фрейма данных и переменной
У меня есть пользовательская функция, которая суммирует переменную. Я упростил функцию, чтобы проиллюстрировать мою проблему, т.е. она более сложна, чем показано ниже. Обратите внимание, что общая структура функции должна оставаться неизменной: она принимает аргумент для указания, над каким кадром данных работать (df
) и аргумент, какую переменную суммировать (variable_to_test
).
my_fun <- function(df, variable_to_test) {
variable_to_test <- enquo(variable_to_test)
new_var_name <- paste0(quo_name(variable_to_test), "_new_name")
df %>%
summarise(
!!new_var_name := sum(!!variable_to_test, na.rm = TRUE)
)
}
Используя пример, я могу применить функцию к каждой переменной в моем фрейме данных:
library(tidyverse)
dat <- tibble(
variable_1 = c(1:5, NA, NA, NA, NA, NA),
variable_2 = c(NA, NA, NA, NA, NA, 11:15)
)
> my_fun(dat, variable_1)
# A tibble: 1 x 1
variable_1_new_name
<int>
1 15
> my_fun(dat, variable_2)
# A tibble: 1 x 1
variable_2_new_name
<int>
1 65
Но: как я могу применить эту функцию ко всем столбцам в кадре данных? Я старался
> dat %>%
+ lapply(., my_fun)
Error in duplicate(quo) : argument "quo" is missing, with no default
Called from: duplicate(quo)
но это возвращает ошибку. Я борюсь с тем фактом, что функция принимает аргумент для работы с кадром данных и для суммирования переменной. Обратите внимание, что я хотел бы сохранить эту структуру - я считаю более элегантным передавать имя фрейма данных в функцию, а не просто назначать функции имя переменной и "жестко кодировать" фрейм данных в теле функции. У кого-нибудь есть хорошая идея, как lapply()
функция?
2 ответа
О, я думаю, что вы просто наносите на карту не ту вещь. Для решения Tidyverse я бы попробовал:
map(dat, ~my_fun(dat, .))
Что это делает, это сопоставить имена столбцов и подключить столбец к .
,
Вы работаете на неправильном уровне. Если вы отображаете функцию на фрейм данных, то эта функция должна занять столбец. Проблема здесь в том, что функция my_fun()
ожидает фрейм данных, а не столбец.
Вам нужно найти какой-то другой способ решения проблемы. Одним из решений является использование картографов, предоставляемых dplyr:
dat %>%
summarise_all(sum, na.rm = TRUE) %>%
rename_all(paste0, "_new_name")
Вы могли бы эквивалентно использовать комбинацию map()
а также set_names()
от мурлыкания
dat %>%
map_df(sum, na.rm = TRUE) %>%
set_names(paste0, "_new_name")