假设我有两个对象,a
和b
,以及R中的函数f1
a<- 5
b<- 10
f1<-function(){
out<- a+b
return(out)
我想编写一个for循环,通过更改它们并再次运行该函数来评估此函数对a
和b
的值的敏感度。我想创建一个对象的向量,然后像这样运行一些代码:
params<- c(a,b)
for(i in params){
store<- i #save the initial value of the object so I can restore it later.
base<-f1() #save function output with original object value
i<- i*1.1 #increase object value by 10%
base.10<- f1() #recalculate and save function output with new object value
calc<- base.10/base #generate a response metric
i<- store #reset the object value to its original value
return(calc)
}
答案 0 :(得分:1)
听起来你有一个函数f1
依赖于对象a
和b
(在该函数中没有定义),你想要测试其输出的灵敏度至a
和b
的值。解决此问题的一种方法是循环遍历灵敏度分析所需的值并操纵f1
的父环境,以便它使用以下值:
f1 <- function() a + b
sensitivity <- function(params) {
old.f1.env <- environment(f1)
grid <- expand.grid(lapply(params, function(x) x * c(1, 1.1)))
grid$outcome <- apply(grid, 1, function(x) {
for (n in names(x)) {
assign(n, x[n])
}
environment(f1) <- environment()
ret <- f1()
environment(f1) <- old.f1.env
ret
})
grid
}
sensitivity(list(a=5, b=10))
# a b outcome
# 1 5.0 10 15.0
# 2 5.5 10 15.5
# 3 5.0 11 16.0
# 4 5.5 11 16.5
在这里,我们已经执行了a
和b
值网格的函数值计算,包括原始a
和b
值以及10 %增加值。
请注意,我们的许多工作来自于在f1
的父环境中指定变量。我建议您重新构建代码,以便函数f1
将相关参数作为输入。然后你可以使用:
f1 <- function(a, b) a + b
sensitivity <- function(params) {
grid <- expand.grid(lapply(params, function(x) x * c(1, 1.1)))
grid$outcome <- apply(grid, 1, function(x) do.call(f1, as.list(x)))
grid
}
sensitivity(list(a=5, b=10))
# a b outcome
# 1 5.0 10 15.0
# 2 5.5 10 15.5
# 3 5.0 11 16.0
# 4 5.5 11 16.5
答案 1 :(得分:1)
这听起来像是一个完美的闭包用例。
(p+1)
然后:
get_f1 <- function(a, b) {
f1<-function(){
out<- a+b
return(out)
}
return(f1)
}
所以在循环中你可以做到:
my_f1 <- get_f1(a=5, b=10)
my_f1() #uses a=5 and b=10 because they are defined in the envir associated with my_f1
显然,您可以使用参数base <- (get_f1(a, b))()
base.10 <- (get_f1(a*1.1, b*1.1))()
定义get_f1
。
使用闭包(附加到环境的功能)而不是修改环境!
tl; dr:闭包很棒
答案 2 :(得分:1)
阅读你的一些评论,我认为这实际上就是你想要的:sensitivity
接受一个函数和一个参数列表,并将函数的敏感性返回给它的参数。 (顺便说一句,你所说的灵敏度,已经意味着something else)
sensitivity <- function(fun, args) {
out <- lapply(names(args), function(cur) {
base10 <- do.call(fun, `[[<-`(args, cur, `[[`(args,cur)*1.1))
base10 / do.call(fun, args)
})
names(out) <- names(args)
return(out)
}
示例:
f1 <- function(a,b) a+b
a1 <- list(a=5, b=2)
sensitivity(f1, a1)
这给出了
$a
[1] 1.03
$b
[1] 1.07
示例2:
f2 <- function(x, y, z) x^2 +3*y*z
sensitivity(f2, list(x=1, y=2, z=3))
$x
[1] 1.011053
$y
[1] 1.094737
$z
[1] 1.094737
它可以正常运行&#34;即插即用&#34;任何功能,但它要求你以不同的方式定义f(可以说,正确)。我可以编写一些可以与你的函数f一起使用的东西,但它会有很多工作和糟糕的味道。如果你想要代码模块化,你就是不能使用副作用......
PS:如果您希望返回一个向量而不是列表,只需在lapply
的定义中将sapply
更改为sensitivity
。
这将给出最后一个例子:
> sensitivity(f2, list(x=1, y=2, z=3))
x y z
1.011053 1.094737 1.094737
PPS:你没有计算f的梯度而不是做你正在做的事情的任何理由?