除非存在可选参数,否则计算平均值的导数?

时间:2016-05-17 02:25:54

标签: r

假设我有一个函数yposition,其中y=f(x1, x2, v1)x1是连续变量而x2v10。例如:

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

唉,我想不出一种编写带有可选参数的函数的方法。

1 个答案:

答案 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的最终函数调用的evalparse方式可能不是最佳方式,但不幸的是,我现在无法想出更好的方法。有时我会在阅读某些R软件包的源代码时看到numDeriv::gradmatch.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]]" ,如果您只想返回一个值。