J'essaie d'analyser l'entrée de l'utilisateur en tant qu'arguments d'un appel de fonction (dans une expression). On dirait que je suis proche mais !!! met mes arguments entre parenthèses, ce qui ne fonctionne pas. J'essaie de recréer ce qui suit avec les entrées utilisateur :

recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>% 
  step_log(disp, base = 10, offset = 0) %>% 
  prep()
library(rlang)
library(tidymodels)

user_dv <- "mpg"
user_idv <- c("cyl", "hp", "wt", "disp")

user_step <- "log"
user_selector <- "disp"
user_args <- "base = 10, offset = 0"

formula <- as.formula(paste(user_dv, paste(user_idv, collapse = " + "), sep = " ~ "))

rcp <- expr(recipe(!!formula,data = mtcars))

add_step <- function(x, step, selector, args){
  f <- parse_expr(paste0("step_", step))
  vars <- ensym(user_selector)
  
  args <- args %>% 
    str_replace(",", ";") %>% 
    parse_exprs()

  step_expr <- call2(f, vars, !!!args)
  
  expr(!!x %>% !!step_expr)
  
}

rcp %>% 
  add_step(user_step, user_selector, user_args) %>% 
  eval() %>% 
  prep()

Mon expression finit par ressembler à ceci :

recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>% 
      step_log(disp, (base = 10), (offset = 0))

Ce qui ne se prépare pas ()

1
sparkplug49 8 oct. 2020 à 19:36

1 réponse

Meilleure réponse

Après parse_exprs(), vous vous retrouvez avec des expressions d'affectation stockées dans une liste sans nom :

# [[1]]
# base = 10
#
# [[2]]
# offset = 0

Tandis que, pour obtenir l'effet souhaité avec !!!, ils doivent être des valeurs dans une liste nommée :

# $base
# [1] 10
#
# $offset
# [1] 0

Cela dit, je suggère plutôt de "transférer les points", car cela conduit à une implémentation plus simple et plus flexible :

add_step <- function(x, step, selector, ...){
  f <- parse_expr(paste0("step_", step))
  vars <- sym(selector)
  step_expr <- call2(f, vars, ...)      # <---- forwarding the dots here

  expr(!!x %>% !!step_expr)
}

L'utilisateur peut maintenant simplement fournir les arguments souhaités directement à add_step() :

rcp %>% add_step(user_step, user_selector, base=10, offset=0)

# recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>% 
#    step_log(disp, base = 10, offset = 0)

OU stockez-les dans une liste et utilisez !!! sur votre fonction :

user_args <- list(base = 10, offset=0)
rcp %>% add_step(user_step, user_selector, !!!user_args)
2
Artem Sokolov 23 oct. 2020 à 14:55