Jautis
Jautis

Reputation: 469

Debugging optimization of a function

I have a function that works just fine when asked to calculate the -logLik given parameters. However, if I try to optimize the function it returns an error message. I'm familiar with debug() to work through problems with a function, but how would I go about debugging optimization for a function that othwerwise works?

Lik <- function(params, data) { 
....
return(-log( **likelihood equation** ))
}

These work!

Lik(params=c(3,10,2,9,rowMeans(data[1,])[1]), data = data1)
Lik(params=c(3,10,2,9.5,rowMeans(data[1,])[1]), data = data1)

GENE1 32.60705

GENE1 32.31657

This doesn't work!

optim(params=c(3,10,2,9,rowMeans(data[1,])[1]), data = data1, Lik, method = "BFGS")

Error in optim(params = c(3, 10, 2, 9, rowMeans(data[1, ])[1]), data = data1, : cannot coerce type 'closure' to vector of type 'double'

Upvotes: 2

Views: 827

Answers (2)

Aaron - mostly inactive
Aaron - mostly inactive

Reputation: 37754

The optim parameter name for the parameters to optimize over is par, not params. You don't need to change your Lik function, it just needs to have the parameters to optimize over as the first argument, the name doesn't matter.

This should work. Here I name the fn argument too, but because the others are named the positional finding works.

optim(par=c(3, 10, 2, 9, rowMeans(data[1, ])[1]), 
      data=data1, fn=Lik, method="BFGS")

So what was happening in your code was that it was saving both params and data to send to the function, and then the first unnamed parameter was Lik so it was getting matched to the first parameter of optim, which is par, the parameters to optimize over. That parameter should be a numeric (a double, technically) but you were sending it a function (a closure, technically), hence the error message.

To debug, you could have turned on debugging for optim debug(optim) and then at the first browse, explored what the parameters were that it was using. You would have found exactly this, though simply in exploring the parameters, you would have discovered you named them incorrectly.

Browse[2]> print(par)
function(params, data) {... return(-log( **likelihood equation** ))}
Browse[2]> print(fn)
Error in print(fn) : argument "fn" is missing, with no default

Upvotes: 1

S.C
S.C

Reputation: 740

It is bad practice to use built-in function names as object names created (or to be created) by the user.

When there is no "data" object (a matrix or a data frame) yet created by the user, R interpreter scans the environments and finds that the only object named "data" is the built in "data" function:

> class(data)
[1] "function"
> str(data)
function (..., list = character(), package = NULL, lib.loc = NULL, verbose = getOption("verbose"), 
    envir = .GlobalEnv)  

Hence R treats the "data" object as a closure (a function declaration) that cannot be subsetted:

> data[1]
Error in data[1] : object of type 'closure' is not subsettable

So you should change the name of the parameter to sth other than data.

And a second point, the syntax of optim is:

optim(par, fn, gr = NULL, ...,
           method = c("Nelder-Mead", "BFGS", "CG", "L-BFGS-B", "SANN",
                      "Brent"),
           lower = -Inf, upper = Inf,
           control = list(), hessian = FALSE)

So in your example, the second parameter supplied to optim should be the function Lik, not the data. And the interpreter tries to interpret data1 as a closure. You can try to swap the positions of data1 and Lik.

And more importantly as @李哲源ZheyuanLi also points, there is no parameter in optim named as "data". You should just write it as "data1" in place of the additional function parameters "...".

And last, as also @Aaron pointed out, the first parameter is named "par" not params".

Upvotes: 0

Related Questions