ラッペマリー
ラッペマリー

Reputation: 23

Create multiple functions/varying arguments in R using a list

I'm trying to create multiple functions with varying arguments.

Just some background: I need to compute functions describing 75 days respectively and multiply them later to create a Maximum-Likelihood function. They all have the same form, they only differ in some arguments. That's why I wanted to this via a loop.

I've tried to put all the equations in a list to have access to them later on. The list this loop generates has 75 arguments, but they're all the same, as the [i] in the defined function is not taken into account by the loop, meanging that the M_b[i] (a vector with 75 arguments) does not vary.

Does someone know, why this is the case?

simplified equation used

for (i in 1:75){
  log_likelihood[[i]] <- 
list(function(e_b,mu_b){M_b[i]*log(e_b*mu_b))})
}

I couldn't find an answer to this in different questions. I'm sorry, if there's a similar thread already existing.

Upvotes: 1

Views: 282

Answers (1)

StupidWolf
StupidWolf

Reputation: 46908

you need to force the evaluation of the variable M_b[i], see https://adv-r.hadley.nz/function-factories.html. Below I try and make it work

func = function(i){
    i = force(i)
    f = function(e_b,mu_b){i*log(e_b*mu_b) }
    return(f)
}

# test
func(9)(7,3) == 9*log(7*3)


#some simulated values for M_b
M_b = runif(75)
log_likelihood = vector("list",75)

for (idx in 1:75){
  log_likelihood[[idx]] <- func(M_b[idx])
}
# we test it on say e_b=5, mu_b=6
test = sapply(log_likelihood,function(i)i(5,6))
actual = sapply(M_b,function(i)i*log(5*6))
identical(test,actual)
[1] TRUE

This is called lazy evaluation, where R doesn't evaluate an expression when it is not used. As correctly pointed about by @SDS0, the value you get is at i=75. We try it with your original function:

func = function(i){function(e_b,mu_b){i*log(e_b*mu_b) }}
M_b = 1:3
log_likelihood = vector("list",3)
for (idx in 1:3){
       log_likelihood[[idx]] = func(M_b[idx])
     }
sapply(log_likelihood,function(f)f(5,6))

[1] 10.20359 10.20359 10.20359
#you get 10.20359 which is M_b[3]*log(5*6)

There is one last option, which I just learned of, which is to do lapply which no longer does lazy evaluation:

func = function(i){function(e_b,mu_b){i*log(e_b*mu_b) }}
log_likelihood = lapply(1:3,function(idx)func(M_b[idx]))
sapply(log_likelihood,function(f)f(5,6))

[1]  3.401197  6.802395 10.203592

Upvotes: 1

Related Questions