【问题标题】:How do I return a data-variable in an R function?如何在 R 函数中返回数据变量?
【发布时间】:2020-07-10 14:21:02
【问题描述】:

我要做什么

我正在尝试编写一个返回数据集某些变量名称的函数。对于一个测试小标题test <- tibble(x1 = 1:3, x2=2:4, x3=3:5, x4=4:6),我想要一个函数

assign_predictors_argument <- function(dataset, outcome, predictors) {
  ...
}

这样:

  1. 如果未定义参数predictors,则predictors 将设置为dataset 中除outcome 之外的所有变量。例如。 assign_predictors_argument(test, x1) 将返回 c(x2, x3, x4)
  2. 如果定义了参数predictors,将返回该值。例如。 assign_predictors_argument(test, x1, c(x2, x3)) 将返回 c(x2, x3)

我的尝试

assign_predictors_argument <- function(dataset, outcome, predictors) {
  if(missing(predictors)) {
    predictors <- dataset %>%
      dplyr::select( -{{ outcome }} ) %>%
      names()
  }
  predictors
}

出了什么问题

案例 1:缺少预测变量参数

assign_predictors_argument(test, x1) 给出结果"x2" "x3" "x4"。但是,我希望它返回 c(x2,x3, x4)

如何将此字符向量转换为输入的形式?

案例 2:定义的预测变量参数

assign_predictors_argument(test, x1, c(x2, x3)) 给了

Error in assign_predictors_argument(test, x1, x2) : 
  object 'x2' not found

函数的最后一行似乎试图评估并返回predictors。由于环境中没有定义x3,所以会报错。

我尝试过 a) 将最后一行更改为 {{predictors}} 以及 b) 将 missing(predictors) 更改为 is.null(predictors) 并输入默认的 predictors = NULL(在 this 之后)。两者都没有工作。

如何在不 a) 更改其形式或 b) 对其进行评估的情况下返回 predictors 的值?

【问题讨论】:

  • “我希望它返回 c(x2,x3,x4)”到底是什么意思?您的意思是包含这些变量的数据框吗?你的意思是一个化解的 R 表达式?

标签: r lazy-evaluation evaluation tidyeval


【解决方案1】:

你很亲密:

assign_predictors_argument <- function(dataset, outcome, predictors) {
  if(missing(predictors)) {
    dataset %>%
      dplyr::select( -{{ outcome }} ) %>%
      names() %>%
      {rlang::expr( c(!!!syms(.)) )}
  }
  else rlang::enexpr(predictors)
}

assign_predictors_argument(test, x1)
# c(x2, x3, x4)
assign_predictors_argument(test, x1, c(x2, x3))
# c(x2, x3)

在上面,rlang::expr() 通过以下方式构造您想要的表达式:1) 使用 syms() 将名称转换为符号,以及 2) 使用 unquote-splice 运算符 !!!c(...) 表达式中将它们拼接在一起。

对于第二部分,您可以简单地捕获用户使用rlang::enexpr() 提供的表达式。

【讨论】:

    【解决方案2】:

    你说你想返回类似c(x2, x3, x4)的东西。我们先搞清楚这个对象是什么。它是函数c 的未评估call。它不是名称向量。您将能够在整洁的评估中使用它,但它需要 !! 运算符。

    这很难实现。您需要捕获predictors 参数并确保它是单个变量名或对c 的调用。传递给predictors 的任何其他表达式都可能会引发错误。

    如果predictors 丢失并且您将列名称作为字符获取,那么您必须将它们转换为带有as.name 的名称并将它们粘贴到c 调用中。如果predictors 是单个变量,则必须返回未计算的值。如果它是一个c 调用,它也应该不经评估返回。否则会抛出错误。

    所以函数可能看起来像这样:

    assign_predictors_argument <- function(dataset, outcome, predictors) {
      if(missing(predictors)) {
        predictors <- dataset %>%
          dplyr::select( -{{ outcome }} ) %>%
          names() %>%
          sapply(as.name, USE.NAMES = FALSE)
          predictors <- as.call(c(quote(c), predictors))
      } else {
       predictors <- as.list(match.call())$predictors
       if(is.call(predictors))
       {
         f_name <- as.list(predictors)[[1]]
         if(as.character(substitute(f_name)) != "c")
           stop("'predictors' must be either a single variable or vector of names")
       }
      }
      predictors
    }
    

    所以让我们测试一下:

    test <- dplyr::tibble(x1 = 1:3, x2 = 2:4, x3 = 3:5, x4 = 4:6)
    
    # Test with missing predictors
    assign_predictors_argument(test, x1)
    #> c(x2, x3, x4)
    
    # Test with single predictor
    assign_predictors_argument(test, x1, x2)
    #> x2
    
    # Test with multiple predictors
    assign_predictors_argument(test, x1, c(x3, x4))
    #> c(x3, x4)
    
    # Test with call other than call to c
    assign_predictors_argument(test, x1, as.name("x3"))
    #> Error in assign_predictors_argument(test, x1, as.name("x3")): 
    #>  'predictors' must be either a single variable or vector of names
    

    这一切看起来都是正确的。所以要使用它,我们可能会这样做:

    vars <- assign_predictors_argument(test, x1, c(x2, x4))
    
    vars
    #> c(x2, x4)
    
    test %>% select(!!vars)
    #> # A tibble: 3 x 2
    #>      x2    x4
    #>   <int> <int>
    #> 1     2     4
    #> 2     3     5
    #> 3     4     6
    

    reprex package (v0.3.0) 于 2020-07-10 创建

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-13
      • 2010-09-07
      • 1970-01-01
      相关资源
      最近更新 更多