Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
622 views
in Technique[技术] by (71.8m points)

r - Tidy evaluation programming with dplyr::case_when

I try to write a simple function wrapping around the dplyr::case_when() function. I read the programming with dplyr documentation on https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html but can't figure out how this works with the case_when() function.

I have the following data:

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

And the following list:

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

Then I would like to write a function like:

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

Unfortunately category_fn(data,cat) gives an evaluation error in this case. I would like to obtain the same output as the output obtained by:

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

What is the way to do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

1) pass list Using let from the wrapr package and data and cat from the question this works without modifying the inputs in any way.

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

giving:

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

1a) Using tidyeval/rlang and data and cat from the question:

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)

giving same result as above.

2) pass list components separately If your intention was to pass each component of cat separately instead of cat itself then this works:

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

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

giving:

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

2a) If you prefer tidyeval/rlang then this case is straight forward:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...