Аргумент функции, который зависит от аргументов по умолчанию - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь написать функцию с аргументами по умолчанию в R. Последний аргумент говорит мне, как пользователь хотел бы, чтобы вычислялась переменная 'g'.По умолчанию это «s + a» (сумма двух предыдущих аргументов), но в принципе это может быть указано любой функцией (например, «s - a» или «s * a» ...).

myFunc <- function(n, 
                   s = rbernoulli(n, p = 0.5), 
                   a = rnorm(n,sd = 2),2),
                   g = s + a){
      data.frame(s = factor(s),
                 a = a,
                 g = as.numeric(g>0))
}

Это прекрасно работает, если я вызываю саму функцию:

myFunc(5)

Чтобы указать, как я хочу вычислить 'g', я хотел бы сделать это:

myFunc(n = 5, g = a - s) (I)

или

myFunc(n = 5, a = ., s = ., g = a - s) (II)

Кажется (I) заставит R искать переменные s / a в рабочей области, а это не то, что мне нужно.И (II) не существует, но я бы сказал: «используйте для него вычисления по умолчанию».

Я попытался указать свою функцию с NULL, но это тоже не сработало.Обратите внимание, что я хотел бы иметь возможность использовать «g» внутри функции после того, как у меня есть ее значение (например, я не могу заменить ее функцией).

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Проблема в том, что g оценивается в вызывающей среде, а не в среде в пределах myFunc.Вы можете добавить аргумент, который определяет среду для оценки g и использовать значение по умолчанию environment(), чтобы оно по умолчанию соответствовало среде в пределах myFunc2.

myFunc2 <- function(n, 
                   s = rbernoulli(n, p = 0.5), 
                   a = rnorm(n,sd = 2),
                   g,
                   envir = environment()) {
      g <- if (missing(g)) s + a else eval(substitute(g), envir)
      data.frame(s = factor(s),
                 a = a,
                 g = as.numeric(g>0))
}
myFunc2(n = 5, g = s + a)
0 голосов
/ 19 февраля 2019

Это можно сделать с помощью нестандартной оценки.Это можно реализовать несколькими способами.Я сейчас в основном использую каверсы и rlang::eval_tidy.Вот реализация вашей функции, использующая это:

library(purrr)
library(rlang)
myFunc <- function(
  n, 
  s = rbernoulli(n, p = 0.5), 
  a = rnorm(n, sd = 2),
  g = s + a) {
  if (!missing(g)) {
    g <- eval_tidy(enquo(g), list(s = s, a = a))
  }
  data.frame(s = factor(s),
             a = a,
             g = as.numeric(g>0))
}

Это будет работать, используя предложенный вами пример myFunc(n = 5, g = a - s).Если аргумент g не предоставлен, по умолчанию используется стандартная функциональность r для вычисления выражения по умолчанию в контексте других параметров.

Обратите внимание, что это также работает с квази-цитатой, поэтому вы можете сделать что-то вроде этого:

my_expr <- expr(a - s)
myFunc(n = 5, g = !!my_expr)

Есть пара великих глав о нестандартных оценках в Продвинутый Хэдли Уикхем R .

Использование только базы R (за исключением purrrr:bernoulli, который вы поставили):

library(purrr)
myFunc <- function(
  n, 
  s = rbernoulli(n, p = 0.5), 
  a = rnorm(n, sd = 2),
  g = s + a) {
  if (!missing(g)) {
    g <- eval(substitute(g), list(s = s, a = a))
  }
  data.frame(s = factor(s),
             a = a,
             g = as.numeric(g>0))
}
0 голосов
/ 19 февраля 2019

Я думаю, что лучший способ сделать это - сделать g функцией, которая принимает два аргумента, s и a.Затем при необходимости вы можете передать другую функцию:

myFunc <- function(n,
                   s = purrr::rbernoulli(n, p = 0.5),
                   a = rnorm(n, sd = 2),
                   g = function(s, a) { s + a }) {
    g_val = g(s, a)
    data.frame(s = factor(s),
               a = a,
               g = as.numeric(g_val > 0))
}

myFunc(5)
myFunc(5, g = function(s, a) { s - a })
...