2017-11-21 101 views
6

Poszukuje bardziej efektywnego/eleganckiego sposobu przekazywania wielu argumentów do grupy - za pomocą niestandardowej oceny funkcji za pomocą dplyr. Nie chcę korzystać z operatora ..., ale do określania funkcji indywidualnie.Programowanie funkcyjne z dplyr

Mój przypadek użycia to funkcja, która pobiera ramkę danych i tworzy obiekt ggplot o prostszej składni. Oto przykład kodu Chcę zautomatyzować z mojej funkcji:

# 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)) 

chcę połączyć to group_by, podsumować ggplot i geom_line do prostej funkcji, które można karmić X, Y i grupę i niech wykona całą brudną robotę pod maską. Oto co stałam pracować:

# 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) 

czuję się jak obchodzenia group_by jest bardzo nieeleganckie: cytowanie x i group z enquo, następnie unquoting im !! wewnątrz innego podając funkcji quos, tylko do ponownego cytatu je z !!! na następnej linii, ale to jedyna rzecz, którą udało mi się dostać do pracy. Czy jest lepszy sposób to zrobić?

Jest również sposób na uzyskanie ggplot do pobrania !! zamiast substitute? To, co robię, wydaje się niekonsekwentne.

Odpowiedz

4

Problemem jest to, że ggplot nie został zaktualizowany do obsługi jeszcze quosures, więc masz do przekazania to wyrażenia, które można utworzyć z quosures z 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) 

Należy jednak pamiętać, że ggplot zostanie prawie nieuchronnie zaktualizowany z lazyeval do rlang, więc podczas gdy ten interfejs prawdopodobnie będzie działał, najprostsza i bardziej spójna będzie prawdopodobnie wkrótce dostępna.

4

Można po prostu zrobić proste eval.parent(substitute(...)) w ten sposób. Będąc bazą R, działa on konsekwentnie na R i jest prosty do zrobienia. Można nawet użyć zwykłego 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)