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. >