引用for循环中的对象列表

时间:2015-09-28 00:38:25

标签: r for-loop

假设我有两个对象,ab,以及R中的函数f1

a<- 5
b<- 10

f1<-function(){
    out<- a+b
    return(out)

我想编写一个for循环,通过更改它们并再次运行该函数来评估此函数对ab的值的敏感度。我想创建一个对象的向量,然后像这样运行一些代码:

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)    
}

3 个答案:

答案 0 :(得分:1)

听起来你有一个函数f1依赖于对象ab(在该函数中没有定义),你想要测试其输出的灵敏度至ab的值。解决此问题的一种方法是循环遍历灵敏度分析所需的值并操纵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

在这里,我们已经执行了ab值网格的函数值计算,包括原始ab值以及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的梯度而不是做你正在做的事情的任何理由?