6

试图do.call()在 tidy 评估的背景下工作:

library(rlang)
library(dplyr)

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

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

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

有什么区别:

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

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

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

和:

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

do.call(category_fn, c(list(df = data), cat), quote = FALSE)
# Or:
do.call(category_fn, c(list(df = data), cat), quote = TRUE)
# Or:
rlang::invoke(category_fn, c(list(df = data), cat))

它们都给出了相同的错误:

# Error in mutate_impl(.data, dots) : 
#   Evaluation error: object 'item_name' not found.

我使用 进入函数browser(),检查了参数,在expr(mutate(df, category = case_when(!!! cat1)))那里运行(如http://rpubs.com/lionel-/programming-draft中建议的通用调试策略),在两种情况下都有相同的输出:mutate(df, category = case_when(~(item_name == "apple" ~ "fruit"), ~(item_name == "bmw" ~ "car"))).

我也尝试调整enviror.env参数无济于事。

我的理解是它可能与不同的quosure环境有关,但environment(cat1[[1]])也是相同的(<environment: R_GlobalEnv>)。

注意:
这在某种程度上是我试图回答的 dplyr::case_when 的 Tidy 评估编程的后续。

> sessioninfo::session_info()
─ Session info ────────────────────────────────────────────────────────
 setting  value                       
 version  R version 3.4.3 (2017-11-30)
 os       Linux Mint 18               
 system   x86_64, linux-gnu           
 [...]                 

─ Packages ────────────────────────────────────────────────────────────
 package     * version    date       source                             
 [...]                
 dplyr       * 0.7.4      2017-09-28 CRAN (R 3.4.3)                     
 [...]                    
 rlang       * 0.1.6      2017-12-21 CRAN (R 3.4.3)                     
 [...]
4

3 回答 3

3

我们可以创建 'cat' 作为 aquosure然后进行评估 !!!

cat <-  quos(item_name == "apple" ~ "fruit", 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    
于 2017-12-29T17:15:34.370 回答
2

我认为这与另一篇文章类似;引用列表本身与单独引用列表元素不同。

我已经修改了 cat 定义以单独引用元素,并且稍微删除了 quosure 语句并显式命名参数的函数。在 do.call 语句中,第二个参数,即要提供给函数的参数列表,我将 cat 元素作为列表的一部分。

通过这些修改,两个do.call语句和调用将返回与帖子中直接执行相同的结果:

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

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

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

> do.call(category_fn, list(data, cat), quote = FALSE)
# A tibble: 3 x 2
  item_name category
      <chr>    <chr>
1     apple    fruit
2       bmw      car
3       bmw      car
> # Or:
> do.call(category_fn, list(data, cat), quote = TRUE)
# A tibble: 3 x 2
  item_name category
      <chr>    <chr>
1     apple    fruit
2       bmw      car
3       bmw      car
> # Or:
> rlang::invoke(category_fn, list(df = data, cat))
# A tibble: 3 x 2
  item_name category
      <chr>    <chr>
1     apple    fruit
2       bmw      car
3       bmw      car

quote 参数的值在两个 do.call 示例中没有区别。

我发现 quosures 在概念上很困难,并且当前在 Cran 上使用 dplyr vignette 进行的编程并没有变得容易得多。

于 2017-12-29T17:25:19.747 回答
2

我对使用 dplyr::case_when进行 Tidy 评估编程的回应的第 (1a) 部分的答案也适用于此。

如果catdatacategory_fn当前问题相同,则此方法有效。第一行转换catcat_适用于此处的形式。

cat_ <- lapply(cat, function(x) do.call("substitute", list(x))) 
do.call("category_fn", c(list(df = data), cat_))

给予:

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

关于最后的问题,在我对上面链接的原始问题的回答中似乎要求替代 quosures 是使用 wrapr 包和基础 R 解决该问题的解决方案。 seplyr 包,由 wrapr 的作者,也可能是另一种选择。

于 2017-12-29T23:29:29.100 回答