使用字符向量动态生成另一个 R 函数的 R 函数

An R function to dynamically generate another R function using a character vector

我正在围绕 rBayesianOptimizationcaret R 包编写一个包装函数。下面描述的问题是主包装函数内部步骤的一部分。我需要将特定模型的超参数(这是下面 input 表示的)传递给将在高斯过程模型中采样的函数。超参数当前存储在字符向量中。

有没有办法在 R 中使用字符向量动态生成函数?我需要一个实际上创建另一个函数的函数。例如,

# start with this...
input <- c("a","b")

# ...and an intermediate function generates this
test_function <- function(a=a,b=b) {
  d <- data.frame(a=a,b=b)
}

此外,该解决方案需要能够处理各种长度和内容的输入。所以这样的事情也应该有效,

# start with this...
input <- c("c","d","e","f")

# ...and an intermediate function generates this
test_function <- function(c=c,d=d,e=e,f=f) {
  d <- data.frame(c=c,d=d,e=e,f=f)
}

这是一个玩具示例,但足以回答我的问题。

这是对您发布的简单示例的简单回答。听起来您的实际工作可能需要更复杂的方法,但这可能会有所帮助。我敢肯定还有其他方法可以更快地做到这一点。

input <- c("c","d","e","f")

test_function <- function(inputVec) {
  df <- data.frame(inputVec[1], stringsAsFactors = FALSE)
  names(df)[1] <- inputVec[1]
  if(length(inputVec) == 1) {
    return(df)
  }
  else if(length(inputVec) > 1) {
    for(i in seq(2, length(inputVec), 1)) {
      dfNew <- data.frame(inputVec[i], stringsAsFactors = FALSE)
      names(dfNew) <- inputVec[i]
      df <- dplyr::bind_cols(df, dfNew)
    }
    return(df)
  }
}

testDF <- test_function(inputVec = input)

print(testDF)
##  c d e f
##1 c d e f

如果我对你的问题的理解正确,那么你正在寻找一个创建函数的函数,其中第二个函数的参数名称与 input 中的名称(给第一个函数)和值一样,也许数字,由这些参数标记。如果没错,这个怎么样?

create_fun <- function(input) {
  funargs <- paste(input, collapse=', ')
  dfargs <- paste0(input, '=', input, collapse=', ')
  funstr <- paste0(
    sprintf("function(%s) {", funargs),
    sprintf("data.frame(%s)", dfargs),
    "}")
  eval(parse(text=funstr))
}
# example applications:
create_fun(c('a','b'))(a=1, b=8)
##   a b
## 1 1 8
create_fun(c('x','y','z'))(y=1, z=8, x=4)
##   x y z
## 1 4 1 8

一个迟到的答案——可能对最初的问题没有用,但我还是把它贴出来了,因为我花了一点时间来弄清楚它:)。

一种方法是基于 rlang::new_function 中的代码:

doit <- function(i) {
  args <- setNames(lapply(i, as.name),i)
  fn <- call("function", as.pairlist(args), as.call(c(as.name("data.frame"), args)))
  eval(fn, parent.frame())
}

# output
> doit("A")
function (A = A) 
data.frame(A = A)
> doit(c("A", "B"))
function (A = A, B = B) 
data.frame(A = A, B = B)
> doit(c("A", "B", "C"))
function (A = A, B = B, C = C) 
data.frame(A = A, B = B, C = C)