Функциональное программирование с помощью dplyr
Ищите более эффективный / элегантный способ передачи нескольких аргументов в группу, используя нестандартную оценку в функции, использующей dplyr. Я не хочу использовать оператор..., но указывать функции по отдельности.
Мой конкретный пример использования - это функция, которая берет фрейм данных и создает объект ggplot с более простым синтаксисом. Вот пример кода, который я хочу автоматизировать с помощью своей функции:
# create data frame
my_df <- data.frame(month = sample(1:12, 1000, replace = T),
category = sample(head(letters, 3), 1000, replace = T),
approved = as.numeric(runif(1000) < 0.5))
my_df$converted <- my_df$approved * as.numeric(runif(1000) < 0.5)
my_df %>%
group_by(month, category) %>%
summarize(conversion_rate = sum(converted) / sum(approved)) %>%
ggplot + geom_line(aes(x = month, y = conversion_rate, group = category,
color = category))
Я хочу объединить эти group_by, summaze, ggplot и geom_line в простую функцию, с помощью которой я могу кормить x, y и group, и заставить ее выполнять всю грязную работу под капотом. Вот что я получил на работу:
# create the function that does the grouping and plotting
plot_lines <- function(df, x, y, group) {
x <- enquo(x)
group <- enquo(group)
group_bys <- quos(!! x, !! group)
df %>%
group_by(!!! group_bys) %>%
my_smry %>%
ggplot + geom_line(aes_(x = substitute(x), y = substitute(y),
group = substitute(group), color = substitute(group)))
}
# create a function to do the summarization
my_smry <- function(x) {
x %>%
summarize(conversion_rate = sum(converted) / sum(approved))
}
# use my function
my_df %>%
plot_lines(x = month, y = conversion_rate, group = category)
Я чувствую, что обработка group_by довольно не элегантна: цитата x
а также group
с enquo
, затем, цитируя их !!
внутри другой функции цитирования quos
только для того, чтобы повторно закрутить их !!!
на следующей строке, но это единственное, что мне удалось получить на работу. Есть лучший способ сделать это?
Кроме того, есть ли способ получить ggplot, чтобы взять !!
вместо substitute
? То, что я делаю, кажется непоследовательным.
2 ответа
Проблема в том, что ggplot еще не обновлен для обработки предложений, поэтому вы должны передать ему выражения, которые вы можете создавать из предложений с помощью rlang::quo_expr
:
library(tidyverse)
set.seed(47)
my_df <- data_frame(month = sample(1:12, 1000, replace = TRUE),
category = sample(head(letters, 3), 1000, replace = TRUE),
approved = as.numeric(runif(1000) < 0.5),
converted = approved * as.numeric(runif(1000) < 0.5))
plot_lines <- function(df, x, y, group) {
x <- enquo(x)
y <- enquo(y)
group <- enquo(group)
df %>%
group_by(!! x, !! group) %>%
summarise(conversion_rate = sum(converted) / sum(approved)) %>%
ggplot(aes_(x = rlang::quo_expr(x),
y = rlang::quo_expr(y),
color = rlang::quo_expr(group))) +
geom_line()
}
my_df %>% plot_lines(month, conversion_rate, category)
Однако имейте в виду, что ggplot почти неизбежно будет обновлен с lazyeval до rlang, поэтому, хотя этот интерфейс, вероятно, продолжит работать, в скором времени будет возможен более простой и согласованный интерфейс.
Вы могли бы просто сделать прямой eval.parent(substitute(...))
как это. Будучи базой R, она работает последовательно через R и проста в выполнении. Можно даже использовать обычный aes
,
plot_lines <- function(df, x, y, group) eval.parent(substitute(
df %>%
group_by(x, group) %>%
my_smry %>%
ggplot + geom_line(aes(x = x, y = y, group = group, color = group))
))
plot_lines(my_df, month, conversion_rate, category)