Keith Jewell
2008-Aug-18 11:50 UTC
[R] "nested" getInitial calls; variable scoping problems
Hi All,
Another nls related problem (for background, I'm migrating a complicated
modelling package from S-plus to R).
Below I've reduced this to the minimum necessary to demonstrate my problem
(I think); the real situation is more complicated.
Two similar selfStart functions, ssA and ssB.
The 'initial' function for ssB modifies its arguments a little and then
calls getInital for ssA.
In addition to the "x" and the fitted coefficients
("Coeff"), ssA and ssB
have arguments ("A") which are not the same length as the dataframe,
so
cannot be passed as columns of that dataframe.
The initial function for ssA uses eval(... parent.frame()) to find
"A",
which is fine when called from .GlobalEnv. But when called from the initial
function of ssB it can't find (the modified version of) "A" .
If A is assigned as a parameter of the dataframe then getInitial.formula
returns "A" as initial estimates of "Coeff", so that
doesn't work.
I've explored the evaluation frame parent-child structure created by the
nested getInitial calls, but it doesn't seem helpful, and I certainly
couldn't trust my understanding of it.
I'm considering making up the matched call and calling the 'initial'
function of ssA directly, in the same manner as getInitial.selfStart
attr(ssA, "initial"))(mCall = mCall, data = data, LHS = LHS)
or perhaps if I call getInitial thus...
getInitial(ssA, data, mCall, LHS = NULL, ...)
it will call getInitial.selfStart without calling getInitial.formula.
In that case perhaps eval(... parent.frame()) will find the argument?
Or, at least I could attach the argument to the dataframe as a parameter.
But this all seems a but clumsy, and I feel there must be a better way. Any
comments and/or advice will be welcome.
Thanks in advance;
Keith Jewell
-------------------------------------------
code showing the problem:
ssA <- selfStart(
model = function(x, Coeff, A)
{
paste(x, Coeff, A)
},
initial = function(mCall, data, LHS)
{
x <- eval(mCall[["x"]], data, parent.frame())
A <- eval(mCall[["A"]], data, parent.frame())
paste("CoeffA", x, A)
},
parameters = c("Coeff")
)
ssB <- selfStart(
model = function(x, Coeff, A)
{
paste(x, Coeff, A)
},
initial = function(mCall, data, LHS)
{
x <- eval(mCall[["x"]], data, parent.frame())
A <- eval(mCall[["A"]], data, parent.frame())
Amod <- paste(A, "mod in B")
getInitial(y ~ ssA(x, Coeff, Amod), data)
},
parameters = c("Coeff")
)
getInitial(y ~ ssA("this", "that", "other"), data=
data.frame(x=c("test")))
getInitial(y ~ ssB("this", "that", "other"), data=
data.frame(x=c("test")))
---------------------------> sessionInfo()
R version 2.7.1 Patched (2008-08-15 r46352)
i386-pc-mingw32
locale:
LC_COLLATE=English_United Kingdom.1252;LC_CTYPE=English_United
Kingdom.1252;LC_MONETARY=English_United
Kingdom.1252;LC_NUMERIC=C;LC_TIME=English_United Kingdom.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
Keith Jewell
2008-Aug-19 10:12 UTC
[R] "nested" getInitial calls; variable scoping problems: Solved??
Hi All,
I've found a solution to my problems which I think is optimal, but I've
been
wrong before (!!) so comments are welcome.
To avoid scoping problems in the 'inner' getInitial I modify the formula
so
that all variable values are specified explitly in the formula, the inner
getInitial need not search for any values so there are no scoping problems:
-----------------------
ssA <- selfStart(
model = function(x, Coeff, A)
{
paste(x, Coeff, A)
},
initial = function(mCall, data, LHS)
{
x <- eval(mCall[["x"]], data, parent.frame())
A <- eval(mCall[["A"]], data, parent.frame())
paste("CoeffA", x, A)
},
parameters = c("Coeff")
)
ssB <- selfStart(
model = function(x, Coeff, A)
{
paste(x, Coeff, A)
},
initial = function(mCall, data, LHS)
{
A <- eval(mCall[["A"]], data, parent.frame())
Amod <- paste(A, "mod in B")
#-----------------------------------
# Doing a getInitial for (for example) y' ~ ssA(x, Coeff, Amod)
# to avoid scoping problems, specify values in the formula for LHS and
# all ssA arguments except Coeff; i.e. all except attr(ssA, "pnames")
#------------------------------------------------------
object <- y ~ ssA(x, Coeff, A) # define a formula object
object[[2]] <- eval(LHS, data, parent.frame()) # left hand side
values
# name RHS arguments by match.call, then assign values to x and A
object[[3]] <- match.call(get(as.character(object[[3]][[1]])),
object[[3]])
object[[3]]$x <- as.character(eval(mCall[["x"]], data,
parent.frame()))
# x
object[[3]]$A <- Amod # A
getInitial(object, data) # do the getInitial
},
parameters = c("Coeff")
)
getInitial(y ~ ssA("this", "that", "other"), data=
data.frame(x=c("test"),
y=1))
getInitial(y ~ ssB("this", "that", "other"), data=
data.frame(x=c("test"),
y=1))
getInitial(y ~ ssB(x, "that", "other"), data=
data.frame(x=c("test1",
"test2"), y=1:2))
------------------
Hope that helps someone,
Keith Jewell
"Keith Jewell" <k.jewell at campden.co.uk> wrote in message
news:g8bnlj$tkm$1 at ger.gmane.org...> Hi All,
>
> Another nls related problem (for background, I'm migrating a
complicated
> modelling package from S-plus to R).
>
> Below I've reduced this to the minimum necessary to demonstrate my
problem
> (I think); the real situation is more complicated.
>
> Two similar selfStart functions, ssA and ssB.
> The 'initial' function for ssB modifies its arguments a little and
then
> calls getInital for ssA.
> In addition to the "x" and the fitted coefficients
("Coeff"), ssA and ssB
> have arguments ("A") which are not the same length as the
dataframe, so
> cannot be passed as columns of that dataframe.
>
> The initial function for ssA uses eval(... parent.frame()) to find
"A",
> which is fine when called from .GlobalEnv. But when called from the
> initial function of ssB it can't find (the modified version of)
"A" .
>
> If A is assigned as a parameter of the dataframe then getInitial.formula
> returns "A" as initial estimates of "Coeff", so that
doesn't work.
> I've explored the evaluation frame parent-child structure created by
the
> nested getInitial calls, but it doesn't seem helpful, and I certainly
> couldn't trust my understanding of it.
> I'm considering making up the matched call and calling the
'initial'
> function of ssA directly, in the same manner as getInitial.selfStart
> attr(ssA, "initial"))(mCall = mCall, data = data, LHS = LHS)
> or perhaps if I call getInitial thus...
> getInitial(ssA, data, mCall, LHS = NULL, ...)
> it will call getInitial.selfStart without calling getInitial.formula.
> In that case perhaps eval(... parent.frame()) will find the argument?
> Or, at least I could attach the argument to the dataframe as a parameter.
>
> But this all seems a but clumsy, and I feel there must be a better way.
> Any comments and/or advice will be welcome.
>
> Thanks in advance;
>
> Keith Jewell
> -------------------------------------------
> code showing the problem:
> ssA <- selfStart(
> model = function(x, Coeff, A)
> {
> paste(x, Coeff, A)
> },
> initial = function(mCall, data, LHS)
> {
> x <- eval(mCall[["x"]], data, parent.frame())
> A <- eval(mCall[["A"]], data, parent.frame())
> paste("CoeffA", x, A)
> },
> parameters = c("Coeff")
> )
> ssB <- selfStart(
> model = function(x, Coeff, A)
> {
> paste(x, Coeff, A)
> },
> initial = function(mCall, data, LHS)
> {
> x <- eval(mCall[["x"]], data, parent.frame())
> A <- eval(mCall[["A"]], data, parent.frame())
> Amod <- paste(A, "mod in B")
> getInitial(y ~ ssA(x, Coeff, Amod), data)
> },
> parameters = c("Coeff")
> )
> getInitial(y ~ ssA("this", "that", "other"),
data=
> data.frame(x=c("test")))
> getInitial(y ~ ssB("this", "that", "other"),
data=
> data.frame(x=c("test")))
> ---------------------------
>> sessionInfo()
> R version 2.7.1 Patched (2008-08-15 r46352)
> i386-pc-mingw32
>
> locale:
> LC_COLLATE=English_United Kingdom.1252;LC_CTYPE=English_United
> Kingdom.1252;LC_MONETARY=English_United
> Kingdom.1252;LC_NUMERIC=C;LC_TIME=English_United Kingdom.1252
>
> attached base packages:
> [1] stats graphics grDevices utils datasets methods base
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide
> http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>