R 在Lappy中将函数作为参数传递给FUN
我正在设计一个适合模型的包,该模型涉及矩阵列的基展开。我希望扩展是用户定义的,这样任何扩展都是可能的,例如R 在Lappy中将函数作为参数传递给FUN,r,non-standard-evaluation,R,Non Standard Evaluation,我正在设计一个适合模型的包,该模型涉及矩阵列的基展开。我希望扩展是用户定义的,这样任何扩展都是可能的,例如spline::bs,spline::ns,stats::poly。相同的展开式应用于矩阵的每一列。我尝试了eval和substitute的一些组合,但无法使其在嵌套函数中工作 我想做的事 set.seed(123) (材料[,1][,2][,3][,4] #> [1,] -0.56047565 1.2240818 -1.0678237 0.42646422 #> [2,] -0.
spline::bs
,spline::ns
,stats::poly
。相同的展开式应用于矩阵的每一列。我尝试了eval
和substitute
的一些组合,但无法使其在嵌套函数中工作
我想做的事
set.seed(123)
(材料[,1][,2][,3][,4]
#> [1,] -0.56047565 1.2240818 -1.0678237 0.42646422
#> [2,] -0.23017749 0.3598138 -0.2179749 -0.29507148
#> [3,] 1.55870831 0.4007715 -1.0260044 0.89512566
#> [4,] 0.07050839 0.1106827 -0.7288912 0.87813349
#> [5,] 0.12928774 -0.5558411 -0.6250393 0.82158108
#> [6,] 1.71506499 1.7869131 -1.6866933 0.68864025
#> [7,] 0.46091621 0.4978505 0.8377870 0.55391765
#> [8,] -1.26506123 -1.9666172 0.1533731 -0.06191171
#> [9,] -0.68685285 0.7013559 -1.1381369 -0.30596266
#> [10,] -0.44566197 -0.4727914 1.2538149 -0.38047100
fitOoh,你很接近了。你只需要把表达式变成一个函数
fit <- function(x, expr = function(i) splines::bs(i, df = 5)) {
nvars <- ncol(x)
x <- scale(x, center = TRUE, scale = FALSE)
design <- design_mat(x = x, expr = expr, nvars = nvars)
# then fit some model on design
}
fit这里是另一个使用非标准求值来更改调用的解决方案spline::bs(x,df=6)
。其基本思想依赖于使用rlang
包来更改从用户捕获的抽象语法树。下面是解决方案;详细信息如下所示:
fit <- function(expr = splines::bs(x, df = 6)) {
sexpr <- rlang::enexpr(expr)
new_expr <- call2(sexpr[[1]],
call2(`[`, sexpr[[2]],
call2(seq_len,
call2(nrow,
sexpr[[2]])),
sym("i")),
splice(as.list(sexpr)[-c(1:2)]))
seq_col <- call2(seq_len, call2(ncol, sexpr[[2]]))
design <- lapply(eval(seq_col), function(i) eval(new_expr))
# then fit some model on design
}
3.创建spline::bs(x[,i],df=6)
这很棘手,因为我们需要跟踪额外的参数。为此,我们可以使用函数rlang::splice
。如果让foo
作为上面步骤2中创建的表达式,我们可以编写
`call2(sexpr[[1]], foo, splice(as.list(sexpr)[-c(1:2)]))`
请注意,我们从sexpr
中删除了第一个和第二个插槽,它们分别对应于函数和矩阵x
4.创建seq_len(ncol(x))
我们现在在这方面做得很好:call2(seq_len,call2(ncol,sexpr[[2]])
5.将所有内容放在一起并进行评估
这是最后一行lappy(eval(seq_col),function(i)eval(new_expr))
我认为其目的是以编程方式(用sexpr[[2]]替换i
,这几乎像一个占位符。类似于曲线(f(i),xname=“i”).r2evans是的,你是对的。这就是M Turgeon的答案,但要小心:splice()处于提问阶段。不清楚是否真的需要它,因为有其他方法可以避免上面部分讨论的性能问题。
(来自帮助页)
`call2(sexpr[[1]], foo, splice(as.list(sexpr)[-c(1:2)]))`