Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

1 Answer

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...