2017-05-26 5 views
5

Ich versuche, eine einfache Wrapper summarise() beliebige Variablen durch beliebige Gruppen zu schreiben und haben nun Fortschritte Ich habe die correct library version loaded bekam aber bin verwirrt (wieder) über den Umgang mit mehreren unquote Argumente Werte.dplyr-0.6.0 Programmierung unquoting

Ich habe zur Zeit die folgende Funktion ...

table_summary <- function(df  = ., 
          id  = individual_id, 
          select = c(), 
          group = site, 
          ...){ 
    ## Quote all arguments (see http://dplyr.tidyverse.org/articles/programming.html) 
    quo_id  <- enquo(id) 
    quo_select <- enquo(select) 
    quo_group <- enquo(group) 
    ## Subset the data 
    df <- df %>% 
      dplyr::select(!!quo_id, !!quo_select, !!quo_group) %>% 
      unique() 
    ## gather() data, just in case there is > 1 variable selected to be summarised 
    df <- df %>% 
      gather(key = variable, value = value, !!quo_select) 
    ## Summarise selected variables by specified groups 
    results <- df %>% 
      group_by(!!quo_group, variable) %>% 
      summarise(n = n(), 
        mean = mean(value, na.rm = TRUE)) 
    return(results) 
} 

, die dort die meisten die Quere kommt und funktioniert, wenn ich eine Gruppenvariable angeben ...

> table_summary(df = mtcars, id = model, select = c(mpg), group = gear) 
# A tibble: 3 x 4 
# Groups: c(gear) [?] 
     gear variable  n  mean 
     <dbl> <chr> <int> <dbl> 
1   3  mpg 15 16.10667 
2   4  mpg 12 24.53333 
3   5  mpg  5 21.38000 

... aber nicht am group_by(!!quo_group, variable), wenn ich gebe mehr als eine group = c(gear, hp) ...

> mtcars$model <- rownames(mtcars) 
> table_summary(df = mtcars, id = model, select = c(mpg), group = c(gear, hp)) 
Error in mutate_impl(.data, dots) : 
    Column `c(gear, hp)` must be length 32 (the group size) or one, not 64 

Ich ging zurück und wieder liest die programming dplyr documentation und ich las, dass man capture multiple variables mit quos() statt enquo() und dann unquote-splice them with !!!, so versucht ...

table_summary <- function(df  = ., 
          id  = individual_id, 
          select = c(), 
          group = c(), 
          digits = 3, 
          ...){ 
    ## Quote all arguments (see http://dplyr.tidyverse.org/articles/programming.html) 
    quo_id  <- enquo(id) 
    quo_select <- enquo(select) 
    quo_group <- quos(group) ## Use quos() rather than enquo() 
    UQS(quo_group) %>% print() ## Check to see what quo_group holds 
    ## Subset the data 
    df <- df %>% 
      dplyr::select(!!quo_id, !!quo_select, !!!quo_group)) %>% 
      unique() 
    ## gather() data, just in case there is > 1 variable selected to be summarised 
    df <- df %>% 
      gather(key = variable, value = value, !!quo_select) 
    ## Summarise selected variables by specified groups 
    results <- df %>% 
       group_by(!!!quo_group, variable) %>% 
       summarise(n = n(), 
         mean = mean(value, na.rm = TRUE)) 
    return(results) 
} 

... das nun bei der ersten Referenz nicht zu !!!quo_group``within dplyr :: select() regardless of how many variables are specified under group = `...

> table_summary(df = mtcars, id = model, select = c(mpg), group = c(gear)) 
[[1]] 
<quosure: frame> 
~group 

attr(,"class") 
[1] "quosures" 
Error in overscope_eval_next(overscope, expr) : object 'gear' not found 
> traceback() 
17: .Call(rlang_eval, f_rhs(quo), overscope) 
16: overscope_eval_next(overscope, expr) 
15: FUN(X[[i]], ...) 
14: lapply(.x, .f, ...) 
13: map(.x[matches], .f, ...) 
12: map_if(ind_list, !is_helper, eval_tidy, data = names_list) 
11: select_vars(names(.data), !(!(!quos(...)))) 
10: select.data.frame(., !(!quo_id), !(!quo_select), !(!(!quo_group))) 
9: dplyr::select(., !(!quo_id), !(!quo_select), !(!(!quo_group))) 
8: function_list[[i]](value) 
7: freduce(value, `_function_list`) 
6: `_fseq`(`_lhs`) 
5: eval(quote(`_fseq`(`_lhs`)), env, env) 
4: eval(quote(`_fseq`(`_lhs`)), env, env) 
3: withVisible(eval(quote(`_fseq`(`_lhs`)), env, env)) 
2: df %>% dplyr::select(!(!quo_id), !(!quo_select), !(!(!quo_group))) %>% 
     unique() 
1: table_summary(df = mtcars, id = model, select = c(mpg), group = c(gear)) 

Was scheint seltsam, und ich denke, ist die Ursache des Problems ist, dass !!!quo_group (dh UQS(quo_group)) druckt ~gear anstatt eine Liste von quosures als ein print() in die Beispielrechnungen Zugabe zeigt passiert ...

> my_summarise <- function(df, ...) { 
    group_by <- quos(...) 
    UQS(group_by) %>% print() 
    df %>% 
    group_by(!!!group_by) %>% 
    summarise(a = mean(a)) 
    } 
> df <- tibble(
    g1 = c(1, 1, 2, 2, 2), 
    g2 = c(1, 2, 1, 2, 1), 
    a = sample(5), 
    b = sample(5) 
) 
> my_summarise(df, g1, g2) 
[[1]] 
<quosure: global> 
~g1 

[[2]] 
<quosure: global> 
~g2 

attr(,"class") 
[1] "quosures" 
# A tibble: 4 x 3 
# Groups: g1 [?] 
    g1 g2  a 
    <dbl> <dbl> <dbl> 
1  1  1 1.0 
2  1  2 5.0 
3  2  1 2.5 
4  2  2 4.0 

ich ausdrücklich mag die Variablen liefern wir gruppieren möchten, indem sie als Parameter zu meinem Argument aber es funktioniert, wenn ich sie als ... angeben, aber ich beschloss, zu testen, ob meine Funktion arbeitet, wenn die Gruppenvariablen als ...

table_summary <- function(df  = ., 
          id  = individual_id, 
          select = c(), 
          group = c(), 
          digits = 3, 
          ...){ 
    ## Quote all arguments (see http://dplyr.tidyverse.org/articles/programming.html) 
    quo_id  <- enquo(id) 
    quo_select <- enquo(select) 
    ## quo_group <- quos(group) 
    quo_group <- quos(...) 
    UQS(quo_group) %>% print() 
    ## Subset the data 
    df <- df %>% 
      dplyr::select(!!quo_id, !!quo_select, !!!quo_group) %>% 
      unique() 
    ## gather() data, just in case there is > 1 variable selected to be summarised 
    df <- df %>% 
      gather(key = variable, value = value, !!quo_select) 
    ## Summarise selected variables by specified groups 
    results <- df %>% 
       group_by(!!!quo_group, variable) %>% 
       summarise(n = n(), 
         mean = mean(value, na.rm = TRUE)) 
    return(results) 
} 
Versorgung

... aber es funktioniert nicht, quos() wieder unquote-Spleißstellen NULL also die var iables sind weder ausgewählt noch gruppiert nach ...

> table_summary(df = mtcars, id = model, select = c(mpg), gear, hp) 
NULL 
# A tibble: 1 x 3 
    variable  n  mean 
    <chr> <int> <dbl> 
1  mpg 32 20.09062 
> table_summary(df = mtcars, id = model, select = c(mpg), gear) 
NULL 
# A tibble: 1 x 3 
    variable  n  mean 
    <chr> <int> <dbl> 
1  mpg 32 20.09062 

Ich habe jede Methode der mehrere Male durch diesen Zyklus fort mit enquo() und quos() Überprüfung kann aber nicht sehen, wo ich falsch werde und trotz der Programmierung gelesen zu haben dplyr Dokumentation mehrmals.

Antwort

4

IIUC Ihr Beitrag, möchten Sie c(col1, col2) zu group_by() liefern. Dies wird nicht von diesem Verb unterstützt:

group_by(mtcars, c(cyl, am)) 
#> Error in mutate_impl(.data, dots) : 
#> Column `c(cyl, am)` must be length 32 (the number of rows) or one, not 64 

Das ist, weil group_by()mutieren Semantik hat, nicht Semantik zu wählen. Das bedeutet, dass die Ausdrücke, die Sie an group_by() liefern, transformative Ausdrücke sind. Dies ist eine überraschende, aber recht praktische Funktion.Sie zum Beispiel können Gruppe von disp Schnitt in drei Intervalle wie folgt aus:

group_by(mtcars, cut3 = cut(disp, 3)) 

Dies bedeutet auch, dass, wenn Sie c(cyl, am) liefern, wird es die beiden Säulen zusammen und geben einen Vektor der Länge 64, verketten, während es eine erwartete Länge von 32 (die Anzahl der Zeilen).

Ihr Problem ist also, dass Sie einen Wrapper zu group_by(), die Semantik Auswahl hat. Dies ist einfach durch die Verwendung dplyr::select_vars() zu tun, die sich bald auf die neue tidyselect Paket extrahiert werden:

library("dplyr") 

group_wrapper <- function(df, groups = rlang::chr()) { 
    groups <- select_vars(tbl_vars(df), !! enquo(groups)) 
    group_by(df, !!! rlang::syms(groups)) 
} 

Alternativ können Sie das neue group_by_at() Verb wickeln, die wählen Semantik hat:

group_wrapper <- function(df, groups = rlang::chr()) { 
    group_by_at(df, vars(!! enquo(groups))) 
} 

Lassen Sie uns versuchen it out:

group_wrapper(mtcars, c(disp, am)) 
#> # A tibble: 32 x 11 
#> # Groups: disp, am [27] 
#>  mpg cyl disp hp drat wt qsec vs am gear carb 
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 
#> 1 21.0  6 160 110 3.90 2.62 16.5  0  1  4  4 
#> # ... with 22 more rows 

Diese Schnittstelle hat den Vorteil, alle select() Operationen unterstützt durch die Spalten Gruppe auszuwählen.

Beachten Sie, dass ich rlang::chr() als Standardargument verwende, da c()NULL zurückgibt, das nicht von auswählenden Funktionen unterstützt wird (wir können das in der Zukunft ändern). chr() aufgerufen ohne Argumente gibt einen Zeichenvektor der Länge 0 zurück.