I have been trying to sort out an odd issue for the last few days in upgrading package
nlsr (for nonlinear least squares). It generally does much better in finding solutions from
poor starts than nls(), but it does not generate the full nls returned object. I've written a
wrapper wrapnlsr() that calls my nlsr functions then uses the resulting parameters in nls()
to get the nls object. But up to now, neither weights nor subset are allowed. I've not got
to subset, but have been trying weights, with very strange results. The full example is too
much code for the list, so I've faked the nlsr output as "firstcoef" in the example below.
What is troubling is that a hand-run example "works", but using a function to do it fails
when there are weights.
The nls.R code referenced in the example around line 570 may suggest that its handling the
weights may be the culprit here. I don't understand why
eval(substitute(weights), data, environment(formula))
is needed for a fixed numeric vector of weights (as required by the manual).
Any help welcome.
John Nash
The example:
# wterr.R -- reproduce nls error when called from function
rm(list=ls()) # probably not needed, but clear the workspace
tnow <- function(formula, data, start, control, trace) {
firstcoef <- c(b1=199, b2=50, b3=0.3) # as if from another solver
cat("firstcoef:\n")
print(firstcoef)
cat("No weights\n")
second<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE)
second
}
tw <- function(formula, data, start, control, trace, weights) {
firstcoef <- c(b1=199, b2=50, b3=0.3)
cat("firstcoef:\n")
print(firstcoef)
cat("weights:"); print(weights)
secondw<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE, weights=weights)
secondw
}
weed <- c(5.308, 7.24, 9.638, 12.866, 17.069, 23.192, 31.443,
38.558, 50.156, 62.948, 75.995, 91.972)
tt <- 1:12
weeddf <- data.frame(tt, weed)
hobbsu <- weed ~ b1/(1+b2*exp(-b3*tt))
st2 <- c(b1=200, b2=50, b3=0.3)
wts <- 0.5^tt # a straight scaling comes via wts <- rep(0.01, 12)
# From this level, we can do the calculation
firstcoef <- c(b1=199, b2=50, b3=0.3)
# Does NOT work from the function tw with weights, but unweighted OK.
# Is the issue line 570/571 of ./R-4.2.1/src/library/stats/R/nls.R ??
tn2<-tnow(hobbsu, weeddf, st2, control=list(), trace=TRUE)
tn2
tt2<-tw(hobbsu, weeddf, st2, control=list(), trace=TRUE, weights=wts)
tt2
# But we can get it running directly
formula<-hobbsu
data<-weeddf
control<-list()
weights<-wts
second<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE)
second
secondw<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE, weights=weights)
secondw
# And if we rerun the functions AFTER succeeding here, tw now works
tn2<-tnow(hobbsu, weeddf, st2, control=list(), trace=TRUE)
tn2
tt2<-tw(hobbsu, weeddf, st2, control=list(), trace=TRUE, weights=wts)
tt2
[R-pkg-devel] Strange behaviour of function called from within a function
2 messages · John C Nash, Noah Greifer
This is an unfortunate problem caused by non-standard evaluation of the
`weights` argument. It happens with `lm()`, too. To solve it, you should
use do.call(), e.g.,
secondw <- do.call("nls", list(formula, data, firstcoef, control,
algorithm=NULL, TRUE, weights = weights))
The reason this works is that `weights` is evaluated in the `list()` call,
which uses standard evaluation, before being passed to `nls()`, rather than
in the `nls()` call. Using `alist()` instead, which doesn't evaluate its
arguments, creates the same problem. You unfortunately have to do this with
every function that involves nonstandard evaluation.
The error that you get, "invalid type (closure) for variable '(weights)'",
occurs because `nls()` is interpreting `weights` as the function
`weights()`, which is a closure (basically the same thing as a function),
rather than as the argument passed through the `weights` argument of
`tw()`.
Noah
On Fri, Aug 12, 2022 at 6:41 PM J C Nash <profjcnash at gmail.com> wrote:
I have been trying to sort out an odd issue for the last few days in
upgrading package
nlsr (for nonlinear least squares). It generally does much better in
finding solutions from
poor starts than nls(), but it does not generate the full nls returned
object. I've written a
wrapper wrapnlsr() that calls my nlsr functions then uses the resulting
parameters in nls()
to get the nls object. But up to now, neither weights nor subset are
allowed. I've not got
to subset, but have been trying weights, with very strange results. The
full example is too
much code for the list, so I've faked the nlsr output as "firstcoef" in
the example below.
What is troubling is that a hand-run example "works", but using a function
to do it fails
when there are weights.
The nls.R code referenced in the example around line 570 may suggest that
its handling the
weights may be the culprit here. I don't understand why
eval(substitute(weights), data, environment(formula))
is needed for a fixed numeric vector of weights (as required by the
manual).
Any help welcome.
John Nash
The example:
# wterr.R -- reproduce nls error when called from function
rm(list=ls()) # probably not needed, but clear the workspace
tnow <- function(formula, data, start, control, trace) {
firstcoef <- c(b1=199, b2=50, b3=0.3) # as if from another solver
cat("firstcoef:\n")
print(firstcoef)
cat("No weights\n")
second<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE)
second
}
tw <- function(formula, data, start, control, trace, weights) {
firstcoef <- c(b1=199, b2=50, b3=0.3)
cat("firstcoef:\n")
print(firstcoef)
cat("weights:"); print(weights)
secondw<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE,
weights=weights)
secondw
}
weed <- c(5.308, 7.24, 9.638, 12.866, 17.069, 23.192, 31.443,
38.558, 50.156, 62.948, 75.995, 91.972)
tt <- 1:12
weeddf <- data.frame(tt, weed)
hobbsu <- weed ~ b1/(1+b2*exp(-b3*tt))
st2 <- c(b1=200, b2=50, b3=0.3)
wts <- 0.5^tt # a straight scaling comes via wts <- rep(0.01, 12)
# From this level, we can do the calculation
firstcoef <- c(b1=199, b2=50, b3=0.3)
# Does NOT work from the function tw with weights, but unweighted OK.
# Is the issue line 570/571 of ./R-4.2.1/src/library/stats/R/nls.R ??
tn2<-tnow(hobbsu, weeddf, st2, control=list(), trace=TRUE)
tn2
tt2<-tw(hobbsu, weeddf, st2, control=list(), trace=TRUE, weights=wts)
tt2
# But we can get it running directly
formula<-hobbsu
data<-weeddf
control<-list()
weights<-wts
second<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE)
second
secondw<-nls(formula, data, firstcoef, control, algorithm=NULL, TRUE,
weights=weights)
secondw
# And if we rerun the functions AFTER succeeding here, tw now works
tn2<-tnow(hobbsu, weeddf, st2, control=list(), trace=TRUE)
tn2
tt2<-tw(hobbsu, weeddf, st2, control=list(), trace=TRUE, weights=wts)
tt2
______________________________________________ R-package-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel