Как мне вернуть переменную данных в функцию R? - PullRequest
3 голосов
/ 10 июля 2020

То, что я пытаюсь сделать

Я пытаюсь написать функцию, которая возвращает имена определенных переменных набора данных. Для тестового тиббла 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 не определен в среде, это приводит к ошибке.

Я пробовал а) изменить последнюю строку на {{predictors}}, а также б) изменить missing(predictors) на is.null(predictors) и вставить по умолчанию predictors = NULL (после это ). Ни то, ни другое не сработало.

Как я могу вернуть значение predictors без а) изменения его формы или б) его оценки?

Ответы [ 2 ]

2 голосов
/ 16 июля 2020

Вы были близки:

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().

1 голос
/ 10 июля 2020

Вы говорите, что хотите вернуть что-то вроде c(x2, x3, x4). Давайте сначала проясним, что это за объект. Это неоцененный call для функции c. Это не вектор имен. Вы сможете использовать его в аккуратной оценке, но для этого потребуется оператор !!.

Это довольно сложно сделать. Вам нужно захватить аргумент 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

Создано 2020-07-10 пакетом REPEX (v0.3.0)

...