假设我有一个函数yposition
,其中y=f(x1, x2, v1)
和x1
是连续变量而x2
是v1
或0
。例如:
1
我想创建一个函数myfunc <- function(x1, x2, v1){
e <- exp(0.1*x1+0.2*x2+v1)
return(e)
}
,它将数据框,函数作为参数,并具有函数变量的可选参数值。此函数h
应返回带h
的向量。如果不存在可选参数,则以参数的平均值计算dy/dx
。但是,可选地,我希望能够传递一个值,而不是平均值。例如,dy/dx
。这可能吗?
这就是我现在所拥有的:
v1=0
唉,我想不出一种编写带有可选参数的函数的方法。
答案 0 :(得分:1)
进入时:
FUN
是用户输入功能; dx
是一个长度为1的字符向量,给出变量名称(部分)导数相对于(w.r.t); dat
是一个数据框,给出了我们要评估衍生品的所有值; opt
默认为NULL
;但如果给出,必须是一个清单。退出时,它返回一个向量,给出"x1"
的偏导数,在df[[x1]]
进行评估,其他变量固定,可以是df
的列均值,也可以是{ {1}}。
使用OP原始示例的示例调用是:
opt
此功能是:
h(myfunc, "x1", df)
h(myfunc, "x1", df, list(v1 = 1))
h(myfunc, "x1", df, list(x2 = 2, v1 = 0))
h(myfunc, "x2", df, list(x1 = 1.2))
注意,此功能会进行各种检查,但目前不检查所有内容。例如,您可能希望进一步确保:
h <- function(FUN, dx, dat, opt = NULL) {
## check arguments of h
if (missing(FUN)) stop("No given function: FUN")
if (!is.function(FUN)) stop("arguments 'FUN' is not a function!")
if (missing(dx)) stop("No given variable to evaluate partial derivatives: dx")
if (!is.character(dx)) stop("arguments 'dx' must be a character!")
if (length(dx) > 1) stop("arguments 'dx' must be of length 1")
if (missing(dat)) stop("No data provided: dat")
if (!is.data.frame(dat)) stop("arguments 'dat' must be a data frame!")
OPT <- !is.null(opt); if (OPT && !is.list(opt)) stop("optional arguments must be provided as a list!")
## get arguments of FUN
FUN_args <- formalArgs(FUN)
## get column vars of dat
dat_vars <- colnames(dat)
## get names of optional arguments
if (OPT) opt_vars <- names(opt)
## need to ensure dx is both inside dat and a function argument of FUN
if (!dx %in% FUN_args) stop(paste("unknown function argumens of FUN:", dx))
if (!dx %in% dat_vars) stop(paste("variable", dx, "is not in `dat`!"))
## now, let's take care of other arguments of FUN, if there are any
n <- length(FUN_args <- FUN_args[-match(dx, FUN_args)])
if (n > 0) {
## are there optional arguments?
if (OPT) {
## extract optional arguments that are in FUN_args (refining opt)
opt_vars <- FUN_args[FUN_args %in% opt_vars]
opt <- opt[opt_vars]
## excluce opt_vars from dat_vars
FUN_args <- FUN_args[-match(opt_vars, FUN_args)]
}
## now, all remaining FUN_args must be found inside dat_vars
missing_vars <- FUN_args[!FUN_args %in% dat_vars]
if (length(missing_vars)) stop(paste("Those variables are not found from `dat` or `opt`:", missing_vars))
## now, there are no missing vars, so we compute column mean from dat for FUN_args
tmp <- lapply(dat[FUN_args], FUN = mean)
## combine tmp and opt
opt <- c(opt, tmp)
}
## prepare function call!
text <- "numDeriv::grad(FUN, x = dat[[dx]]"
FUN_args <- names(opt)
for (i in 1:length(opt)) {
expr <- paste0("opt[['", FUN_args[i], "']]")
expr <- paste(FUN_args[i], expr, sep = " = ")
text <- paste(text, expr, sep = ", ")
}
expr <- paste0(text,")")
## evaluate partial derivatives
eval(parse(text = expr))
}
是长度为1的数字向量,适用于任何opt[[i]]
; i in 1:length(opt)
进行适当处理。构建对NA
的最终函数调用的eval
,parse
方式可能不是最佳方式,但不幸的是,我现在无法想出更好的方法。有时我会在阅读某些R软件包的源代码时看到numDeriv::grad
,match.call()
,但不完全确定他们在做什么。可能他们是更好的选择?但至少这个功能是有效的,老实说,比工作4-5小时更好。
更新:关于您的评论
我将用数据解释do.call()
正在做什么。您的示例数据框类似于:
h
列意味着:
x1 x2 v1
1 1.79741154 6.484015 0
2 1.59461279 3.655893 1
3 1.59738477 4.053226 1
4 3.41523605 4.079614 0
5 3.84462359 2.871799 1
. . . .
. . . .
现在,
对于 x1 x2 v1
1.921273 4.026466 0.500000
列表中没有可选参数的函数调用h(myfunc, "x1", df)
,它在以下几点返回偏导数:
opt
取 x1 x2 v1
1 1.79741154 4.026466 0.500000
2 1.59461279 4.026466 0.500000
3 1.59738477 4.026466 0.500000
4 3.41523605 4.026466 0.500000
5 3.84462359 4.026466 0.500000
. . . .
. . . .
的所有值,但复制列的含义为df[["x1"]]
和mean(df[["x2"]])
。
对于函数调用mean(df[[v1]])
,它返回以下几点的偏导数:
h(myfunc, "x1", df, opt = list(v1 = 1))
采用 x1 x2 v1
1 1.79741154 4.026466 1
2 1.59461279 4.026466 1
3 1.59738477 4.026466 1
4 3.41523605 4.026466 1
5 3.84462359 4.026466 1
. . . .
. . . .
的所有值,但复制列表示df[["x1"]]
并提供值mean(df[["x2"]])
。
对于函数调用v1 = 1
,它返回以下几点的偏导数:
h(myfunc, "x1", df, opt = list(x2 = 2, v1 = 1))
获取 x1 x2 v1
1 1.79741154 2 1
2 1.59461279 2 1
3 1.59738477 2 1
4 3.41523605 2 1
5 3.84462359 2 1
. . . .
. . . .
的所有值,但复制可选值df[["x1"]]
和x2 = 2
。
对于函数调用v1 = 1
,它返回以下几点的偏导数:
h(myfunc, "x2", df, list(x1 = 1.2))
取 x1 x2 v1
1 1.2 6.484015 0.5
2 1.2 3.655893 0.5
3 1.2 4.053226 0.5
4 1.2 4.079614 0.5
5 1.2 2.871799 0.5
. . . .
. . . .
的所有值,但复制列的平均值为df[["x2"]]
,可选值为mean(df[["v1"]]) = 0.5
。
x1 = 1.2
的与h(myfunc, "x1", df, opt = list(x1 = 1))
具有相同的效果,即h(myfunc, "x1", df)
将忽略h
,因为您将x1 = 1
传递给{ {1}}。
该函数始终返回一个向量,因为我把:
"x1"
而不是
dx
我之所以这样做,是因为我不知道为什么要传递数据框 ## prepare function call!
text <- "numDeriv::grad(FUN, x = dat[[dx]]"
,如果您只想返回一个值。