如何在 R 函数中 return a data-variable?

How do I return a data-variable in an R function?

我正在尝试做什么

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

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

这样:

  1. 如果未定义参数predictorspredictors将被设置为dataset中除outcome之外的所有变量。例如。 assign_predictors_argument(test, x1) 将 return c(x2, x3, x4).
  2. 如果参数 predictors 已定义,将 return 该值。例如。 assign_predictors_argument(test, x1, c(x2, x3)) 将 return 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"。但是,我希望这个 return 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

函数的最后一行似乎试图求值 return predictors。由于 x3 没有在环境中定义,这会带来错误。

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

我怎样才能 return predictors 的值而不 a) 改变它的形式或 b) 评估它?

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

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

如果缺少 predictors 并且您将列名称作为字符获取,则必须将它们转换为具有 as.name 的名称并将它们粘贴到 c 调用中。如果 predictors 是单个变量,则必须 returned 未计算。如果是 c 调用,它也应该 return 未计算。否则会抛出错误。

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

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 创建

你很接近:

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) 在 c(...) 表达式中使用不引号将它们拼接在一起-拼接运算符!!!.

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