2015-09-28 3 views
0

Скажем, у меня есть два объекта, a и b и функцию f1 в RСсылка список объектов в цикле

a<- 5 
b<- 10 

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

Я хочу, чтобы написать цикл, который оценивает чувствительность этой функции до значений 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)  
} 

ответ

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 
+0

Это будет работать, но я действительно хочу определить диапазон значений в контексте текущих значений объекта. Я хочу, чтобы переменная a и переменная b поднялась на 10%> Это связано с тем, что в моей реальной функции у меня много разных переменных, значения которых находятся на разных порядках, поэтому я не могу указать общий набор значений для всех их взять. – colin

+1

@colin OK, я обновился, когда перешел к функции 'чувствительность', чтобы обрабатывать как базовое значение, так и 10% больше, чем базовое значение. – josliber

+0

Это так близко. Есть ли способ передать эту команду вектору объектов, вместо того чтобы изменять функцию каждый раз, когда я добавляю/удаляю параметр? Я хотел бы иметь возможность подключать и воспроизводить этот код для других моделей, которые я запускаю, и просто передать им вектор параметров, на которые я хочу оценить чувствительность, и эти параметры всегда будут заданы как объекты R. – colin

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 с аргументами i=c(a, b).

Используйте закрытие (функция, прикрепленная к окружающей среде), вместо того, чтобы возиться с окружающей средой!

ТЛ; др: затворы являются удивительными

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 

Он работает «подключи -and-play "wi й любой функции, НО это требует, чтобы вы определяли f по-другому (можно сказать, правильно). I мог бы написать что-то, что будет работать с вашей функцией f, как написано, но это будет много работы и плохого вкуса. Если вы хотите модульности кода, вы просто не можете использовать побочные эффекты ...

PS: если вы предпочли бы иметь вектор вернулся вместо списка, просто изменить lapply к sapply в определении sensitivity.

Это дало бы последний пример:

> sensitivity(f2, list(x=1, y=2, z=3)) 
     x  y  z 
1.011053 1.094737 1.094737 

PPS: никаких причин, почему вы не вычисляя градиент е, а не делать то, что вы делаете?

+0

вы можете объяснить больше о том, почему моя функция написана «неправильно», и почему, как вы указали ее правильно? – colin

+0

Если ваша функция использует a и b так же просто, как ваш пример, я не понимаю, в чем преимущество не пропускать a и b как параметры f, особенно учитывая, что область с R может быть действительно неинтуитивной. Я должен сказать, что я нахожу особенно непривлекательным тот факт, что вызов f в разное время с теми же аргументами может дать разные результаты. Это ошибка, склонная без уважительной причины. И это усложняет простые вещи, как то, что вы хотите сделать. Это неверно, но я думаю, что он уступает. –

+0

Если вы хотите перфо; f на 'x' и' y', вы должны теперь делать 'a <-x' и' b <-y', а затем 'f()' вместо 'f (x, y)'. Разве вы не находите это уродливым? Справедливости ради, я часто использую внешнюю переменную в своих функциях, но только потому, что они на самом деле являются фиксированными значениями или значениями, которые я очень редко меняю, следовательно, вряд ли «параметры».Учитывая, что вы изучаете чувствительность f к a и b, я могу только предположить, что a и b являются важными параметрами f и поэтому должны быть явно переданы для удобства и модульности. –

Смежные вопросы