Search code examples
rdata-fittingnls

Diff() incompatable in nlsLM package?


Question: Thank you in advance! does nlsLM not work with diff? I am simply trying to do g*(p[i]-p[i-1])/(x[i]-x[i-1]) and use nlsLM to find the value of fitting parameter g that can fit y I use diff without nlsLM as follows,

`g*diff(df$p)/diff(df$x)`

and it works just fine:

`[1] 0.4 3.0 3.0`

However, when I use it with nlsLM, it does not work and I get the following:

`Error in qr(.swts * attr(rhs, "gradient")) : 
  dims [product 3] do not match the length of object [4]
In addition: Warning messages:
1: In lhs - rhs :
  longer object length is not a multiple of shorter object length
2: In lhs - rhs :
  longer object length is not a multiple of shorter object length
3: In lhs - rhs :
  longer object length is not a multiple of shorter object length
4: In lhs - rhs :
  longer object length is not a multiple of shorter object length
5: In lhs - rhs :
  longer object length is not a multiple of shorter object length
6: In lhs - rhs :
  longer object length is not a multiple of shorter object length
7: In lhs - rhs :
  longer object length is not a multiple of shorter object length
8: In .swts * attr(rhs, "gradient") :
  longer object length is not a multiple of shorter object length`

Code:

# Packages:
library(tidyverse)
library(minpack.lm) 

# undoing tidyverse's masking effects( Courtesy of user Kat)
filter <- dyplr::filter 
lag <- dplyr::lag 

#df
df<-data.frame(x=c(9,14,15,17),p=c(11,13,16,22),y=c(16,19,25,35))

#object

g<-5

#nlsLM run: finding fitting parameter g's value

summary(nlsLM(formula=y~g*diff(p)/diff(x),
              data=df,trace=F,
              start=list(g=5),control=nls.lm.control(maxiter=1000)))

Solution

  • We assume you are interested in the following least squares model where n is nrow(df)

    y[i] ~ g * (p[i] - p[i-1]) / (x[i] - x[i-1]) for i = 2, ..., n
    

    1) nlsLM Now diff(x) is one shorter than x since for the first element there is no prior element to subtract so use this

    y1 <- df$y[-1]
    nlsLM(y1 ~ g * diff(p) / diff(x), df, start = list(g = 5))
    

    giving:

    Nonlinear regression model
      model: y1 ~ g * diff(p)/diff(x)
       data: df
        g 
    10.33 
     residual sum-of-squares: 273
    
    Number of iterations to convergence: 2 
    Achieved convergence tolerance: 1.49e-08
    

    2) nls Note that we could have used nls

    y1 <- df$y[-1]
    nls(y1 ~ g * diff(p) / diff(x), df, start = list(g = 5))
    

    3) lm and since this is linear in the single parameter g we could have used lm as well.

    lm(y[-1] ~ I(diff(p) / diff(x)) + 0, df)
    

    4) dyn The dyn package can handle this automatically with lm and other certain regression functions that use model.frame using zoo or ts.

    library(dyn)
    dyn$lm(y ~ I(diff(p) / diff(x)) + 0, zoo(df))
    

    Added

    Regarding the problem in the comments an error in that comment was introduced by faulty alignment. Try this which for me converges in 6 iterations.

    y1 <- df$y[-1]
    p1 <- df$p[-1]
    pL <- df$p[-nrow(df)]
    
    fo <- y1 ~ g*((   (1/ (1 + exp((g)*((1/p1)-(1/(p1)))))) -
        (1/ (1 + exp((g)*((1/pL)-(1/(p1)))))) ) /(p1-pL))
    nls(fo, start = list(g = 5))