2017-12-29 15 views
11

Ich versuche, eine einfache Funktion um die Funktion dplyr :: case_when() zu wickeln. Ich lese die Programmierung mit dplyr Dokumentation auf https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html aber kann nicht herausfinden, wie dies mit der case_when() Funktion funktioniert.Tidy Auswertung Programmierung mit dplyr :: case_when

Ich habe folgende Daten:

data <- tibble(
    item_name = c("apple", "bmw", "bmw") 
) 

Und die folgende Liste:

cat <- list(
    item_name == "apple" ~ "fruit", 
    item_name == "bmw" ~ "car" 
) 

Dann würde Ich mag eine Funktion schreiben wie:

category_fn <- function(df, ...){ 
    cat1 <- quos(...) 
    df %>% 
    mutate(category = case_when((!!!cat1))) 
} 

Leider category_fn(data,cat) eine gibt Bewertungsfehler in diesem Fall. Ich möchte die gleiche Ausgabe erhalten wie die Ausgabe von:

data %>% 
    mutate(category = case_when(item_name == "apple" ~ "fruit", 
           item_name == "bmw" ~ "car")) 

Was ist der Weg, dies zu tun?

+0

Dies sollte aus der Box funktionieren, gibt es ein GitHub-Problem dafür: https://github.com/tidyverse/dplyr/issues/3133. Verwenden Sie vorerst eine der in der Antwort vorgeschlagenen Alternativen. – krlmlr

Antwort

6

Quote jedes Element der Liste zuerst:

cat <- list(
    quo(item_name == "apple" ~ "fruit"), 
    quo(item_name == "bmw" ~ "car") 
) 

Ihre Funktion hat, um die Katze Objekt selbst dann nicht zu zitieren. Ich habe mich verändert auch die Verwendung der „alles andere“ ... Argument der Kategorie Argument im Aufruf ausdrücklich Bezug zu nehmen:

category_fn <- function(df, categories){ 
    df %>% 
    mutate(category = case_when(!!!categories)) 
} 

Der Ausgang der Funktion wird dann als erwartet:

category_fn(data, cat) 
# A tibble: 3 x 2 
    item_name category 
     <chr> <chr> 
1  apple fruit 
2  bmw  car 
3  bmw  car 

der Vollständigkeit halber stelle ich fest, dass die Kategorienliste mit Ihrer Funktion arbeitet, wenn auch mit der Basis R quote() Funktion definiert:

cat <- list(
    quote(item_name == "apple" ~ "fruit"), 
    quote(item_name == "bmw" ~ "car") 
) 
> cat 
[[1]] 
item_name == "apple" ~ "fruit" 

[[2]] 
item_name == "bmw" ~ "car" 

> category_fn(data, cat) 
# A tibble: 3 x 2 
    item_name category 
     <chr> <chr> 
1  apple fruit 
2  bmw  car 
3  bmw  car 
7

1) passiert Liste Mit let aus dem Wrapr-Paket und data und cat aus der Frage funktioniert dies, ohne die Eingaben in irgendeiner Weise zu ändern.

library(dplyr) 
library(wrapr) 

category_fn <- function(data, List) { 
    let(c(CATEGORY = toString(sapply(List, format))), 
     data %>% mutate(category = case_when(CATEGORY)), 
     subsMethod = "stringsubs", 
     strict = FALSE) 
} 
category_fn(data, cat) # test 

geben:

# A tibble: 3 x 2 
    item_name category 
     <chr> <chr> 
1  apple fruit 
2  bmw  car 
3  bmw  car 

1a) Verwendung tidyeval/rlang und data und cat von der Frage:

category_fn <- function(data, List) { 
    cat_ <- lapply(List, function(x) do.call("substitute", list(x))) 
    data %>% mutate(category = case_when(!!!cat_)) 
} 
category_fn(data, cat) 

wie oben gleiche Ergebnis ergibt.

2) Passliste Komponenten separat Wenn Ihre Absicht jede Komponente cat separat statt cat selbst das funktioniert passieren war dann:

category_fn <- function(data, ...) eval.parent(substitute({ 
    data %>% mutate(category = case_when(...)) 
})) 

category_fn(data, item_name == "apple" ~ "fruit", 
        item_name == "bmw" ~ "car") # test 

geben:

# A tibble: 3 x 2 
    item_name category 
     <chr> <chr> 
1  apple fruit 
2  bmw  car 
3  bmw  car 

2a) Wenn Sie tidyeval/rlang bevorzugen, dann ist dieser Fall gerade:

library(dplyr) 
library(rlang) 

category_fn <- function(data, ...) { 
    cat_ <- quos(...) 
    data %>% mutate(category = case_when(!!!cat_)) 
} 

category_fn(data, item_name == "apple" ~ "fruit", 
        item_name == "bmw" ~ "car") # test