From hb at maths.lth.se  Wed Apr  5 13:58:15 2006
From: hb at maths.lth.se (Henrik Bengtsson)
Date: Wed, 5 Apr 2006 13:58:15 +0200
Subject: [Rd] predict.smooth.spline.fit and Recall() (Was: Re: Return
	function from function and Recall())
In-Reply-To: <Pine.LNX.4.64.0604051109100.12918@gannet.stats.ox.ac.uk>
References: <59d7961d0604050225g4b3235fby3aa13af460fa38f7@mail.gmail.com>
	<Pine.LNX.4.64.0604051109100.12918@gannet.stats.ox.ac.uk>
Message-ID: <59d7961d0604050458uf6ff050r1d714eae5885bcea@mail.gmail.com>

On 4/5/06, Prof Brian Ripley <ripley at stats.ox.ac.uk> wrote:
> On Wed, 5 Apr 2006, Henrik Bengtsson wrote:
>
> > Hi,
> >
> > forget about the below details.  It is not related to the fact that
> > the function is returned from a function.  Sorry about that.  I've
> > been troubleshooting soo much I've been shoting over the target.  Here
> > is a much smaller reproducible example:
> >
> > x <- 1:10
> > y <- 1:10 + rnorm(length(x))
> > sp <- smooth.spline(x=x, y=y)
> > ypred <- predict(sp$fit, x)
> > # [1]  2.325181  2.756166  ...
> > ypred2 <- predict(sp$fit, c(0,x))
> > # Error in Recall(object, xrange) : couldn't find
> > # function "predict.smooth.spline.fit"
>
> It seems Recall is not searching (via findFun) from the right environment,
> but at a quick glance it is not obvious to me why.
> You can replace Recall by predict.smooth.spline.fit for now.

More troubleshooting shows that by dispatching directly on 'sp' and
not 'sp$fit' works.  The reason that I do not want to do this is
related to my questions yesterday that I want to keep the memory usage
down and 'sp' hold quite some extra data even with keep.data=FALSE.

Example show how it works:

x <- 1:10
y <- 1:10 + rnorm(length(x))
sp <- smooth.spline(x=x, y=y)

The following two calls work:

ypred1 <- predict(sp, x)
ypred2 <- predict(sp, c(0,x))

They dispatch on predict.smooth.spline(), which in turn calls
predict(sp$fit, ...) which dispatch on predict.smooth,spline.fit();

> getAnywhere("predict.smooth.spline")
A single object matching 'predict.smooth.spline' was found
It was found in the following places
  registered S3 method for predict from namespace stats
  namespace:stats
with value

function (object, x, deriv = 0, ...)
{
    if (missing(x)) {
        if (deriv == 0)
            return(object[c("x", "y")])
        else x <- object$x
    }
    fit <- object$fit
    if (is.null(fit))
        stop("not a valid \"smooth.spline\" object")
    else predict(fit, x, deriv, ...)
}
<environment: namespace:stats>

Trying to do the same without the first step, that is, to call
predict(sp$fit, ...) to dispatch on predict.smooth,spline.fit()
directly, then the second will fail due to the Recall();

ypred3 <- predict(sp$fit, x)
ypred4 <- predict(sp$fit, c(0,x))  # Error!

Note that both predict.smooth.spline() and predict.smooth.spline.fit()
are under the "namespace hood", i.e. not exported. So, no apparent
difference there.

To avoid the overhead of some of the elements of 'sp' I create a
minimal 'smooth.spline' object like this:

fit <- structure(list(fit=sp$fit), class=class(sp))
ypred5 <- predict(fit, x)
ypred6 <- predict(fit, c(0,x))  # Error!

and it all works.  I don't really like to fake objects like this,
although allowed in S3.  But for now it's ok.  However, it would be
interesting to know/understands what is going on.

/Henrik

[snip]

> >
> > /Henrik
> >
> >
> > On 4/5/06, Henrik Bengtsson <hb at maths.lth.se> wrote:
> >> Hi,
> >>
> >> yesterday I got very useful feedback on what is the best way to return
> >> a function from a function.
> >>
> >> Now, I run into a problem calling a returned function that down the
> >> stream uses Recall().  Below is a self-contained example.  I took away
> >> yesterday's code for returning a minimal environment for the function,
> >> because that is not related to this problem.
> >>
> >> getPredictor <- function(x, y) {
> >>   sp <- smooth.spline(x=x, y=y, keep.data=FALSE)
> >>   function(x, ...) predict(sp$fit, x, ...)$y
> >> }
> >>
> >> # Simulate data
> >> x <- 1:10
> >> y <- 1:10 + rnorm(length(x))
> >>
> >> # Estimate predictor function
> >> fcn <- getPredictor(x,y)
> >>
> >> # No extrapolation => no Recall()
> >> ypred <- fcn(x)
> >> print(ypred)
> >> # Gives:  # [1]  2.325181  2.756166  ...
> >>
> >> # With extrapolation => Recall()
> >> xextrap <- c(0,x)
> >> ypred <- fcn(xextrap)
> >> # Gives:  # Error in Recall(object, xrange) : couldn't find
> >> # function "predict.smooth.spline.fit"
> >>
> >> To see what's the function looks like, do
> >>
> >> pfcn <- getAnywhere("predict.smooth.spline.fit")$obj[[2]]
> >> page(pfcn)
> >>
> >> A workaround is to set the predict.smooth.spline.fit() in .GlobalEnv, i.e.
> >>
> >>  predict.smooth.spline.fit <- pfcn
> >>
> >> Does Recall() have a problem because predict.smooth.spline.fit() is
> >> not exported, or what is going on?  Are there alternatives to the
> >> above workaround?  I can see how such a workaround can become very
> >> complicated with complex functions where it is hard to predict what
> >> functions are called when.
> >>
> >> /Henrik
> >>
> >> PS, may I suggest to modify page() so that
> >> 'page(getAnywhere("predict.smooth.spline.fit"))' works? DS.
> >>
> >
> >
> > --
> > Henrik Bengtsson
> > Mobile: +46 708 909208 (+2h UTC)
> >
> > ______________________________________________
> > R-devel at r-project.org mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
> >
> >
>
> --
> Brian D. Ripley,                  ripley at stats.ox.ac.uk
> Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
> University of Oxford,             Tel:  +44 1865 272861 (self)
> 1 South Parks Road,                     +44 1865 272866 (PA)
> Oxford OX1 3TG, UK                Fax:  +44 1865 272595
>
>


--
Henrik Bengtsson
Mobile: +46 708 909208 (+2h UTC)



[Rd] predict.smooth.spline.fit and Recall() (Was: Re: Return function from function and Recall())
Henrik Bengtsson