0
votes

I've read many similar questions but still couldn't find the answer. Here is some data that I'm using to calibrate the equation below:

set.seed(100)
i <- sort(rexp(n = 100,rate = 0.01))
Tr <- sort(runif(n = 100,min = 5,max = 100))

k_start <- 3259
u_start <- 0.464
t0_start <- 38
n_start <- -1

i_test <- k_start*Tr^u_start * (5 + t0_start)^n_start

m <- nls(i~(k * Tr^u / (5+t0)^n), start = list(k = k_start, u = u_start,
                                               t0 = t0_start, n = n_start))

When I used nlsLM and the same error came up:

Error in nlsModel(formula, mf, start, wts) : singular gradient matrix at initial parameter estimates

For the start values, I tried to use the values from calibration in Python and still the same error occurs.

There's also another way to use that equation that is like this: However, the result is the same error.

d_start <- 43

m <- nls(i ~ (k * Tr^u / d),
         start = list(k = k_start, u = u_start,d=d_start))

When I use only the numerator it works, but that's not what I need. Any help will be very much appreciated.

1

1 Answers

2
votes

In the first nls, the right hand side depends on k, t0 and n only through k / (5+t0)^n so it is over parameterized as one parameter could represent their combined effect. In the second nls the right hand side depends only on k and d through k / d so again the problem has been over parameterized and one parameter could represent their combined effect.

Getting rid of the excess parameters and getting the starting values using a linear model it converges.

fit.lm <- lm(log(i) ~ log(Tr))
co <- coef(fit.lm)
fit <- nls(i ~ k * Tr ^ u, start = list(k = exp(co[[1]]), u = co[[2]]))
fit
## Nonlinear regression model
##   model: i ~ k * Tr^u
##    data: parent.frame()
##         k         u 
## 0.0002139 3.0941602 
##  residual sum-of-squares: 79402
##
## Number of iterations to convergence: 43 
## Achieved convergence tolerance: 5.354e-06

Reciprocal Model

Below we fit a "reciprocal model" which has the same number of parameters but a better fit as measured by the deviance which is the residual sum of squares. A lower value means better fit.

# reciprocal model
fit.recip <- nls(i ~ 1/(a + b * log(Tr)), start = list(a = 1, b = 1))

deviance(fit)
## [1] 79402.17
deviance(fit.recip)
## [1] 25488.1

Graphics

Below we plot both fit (red) and fit.recip (blue) models.

plot(i ~ Tr)
lines(fitted(fit) ~ Tr, col = "red")
lines(fitted(fit.recip) ~ Tr, col = "blue")
legend("topleft", legend = c("fit", "fit.recip"), lty = 1, col = c("red", "blue"))

(continued after plot) screenshot

plinear

Note that the plinear algorithm could be used as an alternative algorithm to fit the fit model above to avoid having to supply a starting value for k. It also has the additional benefit that it requires substantially fewer iterations in this case (14 vs. 45). With plinear the formula should omit the linear argument, k, as it is implied by the algorithm and will be reported as .lin .

nls(i ~ Tr ^ u, start = list(u = co[[2]]), algorithm = "plinear")
## Nonlinear regression model
##   model: i ~ Tr^u
##    data: parent.frame()
##         u      .lin 
## 3.0941725 0.0002139 
##  residual sum-of-squares: 79402
##
## Number of iterations to convergence: 14 
## Achieved convergence tolerance: 3.848e-06