Skip to content

wrapping mle()

7 messages · Sébastien Bihorel, Gabor Grothendieck, Brian Ripley +1 more

#
Hi,

How can we set the environment for the minuslog function in mle()?  The
call in this code fails because the "ll" function cannot find the object
'y'.  Modifying from the example in ?mle:


library(stats4)
ll <- function(ymax=15, xhalf=6) {
    -sum(stats::dpois(y, lambda=ymax/(1+x/xhalf), log=TRUE))
}
fit.mle <- function(FUN, x, y) {
    loglik.fun <- match.fun(FUN)
    mle(loglik.fun, method="L-BFGS-B", lower=c(0, 0))
}
fit.mle("ll", x=0:10, y=c(26, 17, 13, 12, 20, 5, 9, 8, 5, 4, 8))


How should "fit.mle" be constructed so that "ll" works on the appropriate
environment?  Thanks in advance for any advice on this.
#
Add the line marked ### so that the environment of loglik.fun is reset to
the environment within fit.mle so that it can find y there:

library(stats4)
ll <- function(ymax=15, xhalf=6) {
   -sum(stats::dpois(y, lambda=ymax/(1+x/xhalf), log=TRUE))
}
fit.mle <- function(FUN, x, y) {
   loglik.fun <- match.fun(FUN)
   environment(loglik.fun) <- environment() ###
   mle(loglik.fun, method="L-BFGS-B", lower=c(0, 0))
}
fit.mle("ll", x=0:10, y=c(26, 17, 13, 12, 20, 5, 9, 8, 5, 4, 8))
On 12/30/06, Sebastian P. Luque <spluque at gmail.com> wrote:
#
On Fri, 29 Dec 2006, Sebastian P. Luque wrote:

            
You need to set the environment of ll to that containing your data 
objects.  This would happen automatically if you defined ll in the 
function fit.mle.  A brutal solution would be

fit.mle <- function(FUN, x, y) {
    loglik.fun <- match.fun(FUN)
    environment(loglik.fun) <- sys.frame(sys.nframe())
    mle(loglik.fun, method="L-BFGS-B", lower=c(0, 0))
}

but of course that would remove the previous environment from the scope, 
so you may need something like

    env <- sys.frame(sys.nframe())
    parent.env(env) <- environment(ll)
    environment(loglik.fun) <- env
#
On Sat, 30 Dec 2006 07:41:48 +0000 (GMT),
Prof Brian Ripley <ripley at stats.ox.ac.uk> wrote:
[...]
Thanks to both of you.  I really need to get to grips with environments.


Happy new year,
#
It is much cleaner to do this sort of thing with lexical scope.  For
example,

     mkll <- function(x, y) {
        function(ymax=15, xhalf=6) {
           -sum(stats::dpois(y, lambda=ymax/(1+x/xhalf), log=TRUE))
        }
     }

creates a log-likelihood likelyhood function for data x,y that can
then be used by

     fit.mle <- function(mkfun, x, y) {
         loglik.fun <- mkfun(x, y)
         mle(loglik.fun, method="L-BFGS-B", lower=c(0, 0))
     }

as in


     > fit.mle(mkll, x=0:10, y=c(26, 17, 13, 12, 20, 5, 9, 8, 5, 4, 8))

     Call:
     mle(minuslogl = loglik.fun, method = "L-BFGS-B", lower = c(0,
         0))

     Coefficients:
          ymax     xhalf
     24.999420  3.055779

It is not clear why you want to be able to pass ll as a character
string or why you want to assume that the thing passed in will refer
to variables named 'x' and 'y', both usually bad ideas, so this
specific approach may not apply, but something variant should.

The ability to use environment(f)<-env to change the environment of a
function is one of the most dubious language features of R (maybe the
most dubious, though there are a couple of other strong contenders)
and should not be used except in very rare circumstances.

Best,

luke
On Sat, 30 Dec 2006, Gabor Grothendieck wrote:

            

  
    
#
On Sat, 30 Dec 2006 15:46:01 -0600 (CST),
Luke Tierney <luke at stat.uiowa.edu> wrote:

            
Thanks Luke, this looks excellent.
In the real case, I need to provide two different log likelihood
functions, and then tell fit.mle() which one to use in a given call.  I
was actually defining 'x' and 'y' as formal arguments to fit.mle().
Wouldn't that ensure that the original ll() would refer to the correct
variables?  In any case, it was easy to use your suggestion almost by
direct analogy, which makes the code much more readable.  Thanks a lot.

In the case I describe though, why would it be a bad idea to use a string
to refer to the function, and then use match.fun()?  I actually picked up
the idea from functions such as apply() and friends.
Keeping the lexical scoping technique you showed in mind should help stay
away from that.


Cheers,
#
That has two disadvantages:

(1) it only works if the user is defining ll himself; however, if the
user is getting
ll from somewhere else then its not applicable since the user no
longer controls its
scope whereas resetting the environment method still works

(2) its "cleaner" for the developer but harder for the user who is now
forced into
a more complicated construct, i.e. the nested double function construct

By the way, here is one additional solution using the proto package that
avoids explicitly resetting of the environment in favor implicitly setting it.
A new proto object is created which to hold FUN and since proto methods have
their object as their scope, their environment is implicitly reset:

library(proto)
library(stats4)
ll <- function(ymax=15, xhalf=6) {
  -sum(stats::dpois(y, lambda=ymax/(1+x/xhalf), log=TRUE))
}
fit.mle <- function(FUN, x, y)
  mle(proto(FUN = match.fun(FUN))[["FUN"]], method="L-BFGS-B", lower=c(0, 0))
fit.mle("ll", x=0:10, y=c(26, 17, 13, 12, 20, 5, 9, 8, 5, 4, 8))
On 12/30/06, Luke Tierney <luke at stat.uiowa.edu> wrote: