3

I want to estimate the parameters of a non linear model.

The model equation is Z = A * exp(- a * X) + B * exp(- b * Y) + C

  • X and Y are the predictors
  • A, B, a, b are the parameters to estimate

What I did is to transform the model into a linear problem by doing a exponential transformation before doing a linear regression:

  • For a and b between 0 and 1, I compute exp_x = exp(- a * X) and exp_y = exp(- b * Y)
  • I do a linear regression Z ~ exp_x + exp_y

It works very well as we can see in this simulation

x = 1:10
y = 1:10

combination = expand.grid(x = x, y = y)

df = data.frame(
  X = combination$x,
  Y = combination$y,
  Z = 2 * exp(-0.3 * combination$x) + 
      5 * exp(-0.6 * combination$y) + 
      rnorm(n = 100, mean = 0, sd = 0.1 )
)

a_hat = 0
b_hat = 0
best_ols = NULL
best_rsquared = 0

for (a in seq(0.01, 1, 0.01)){
  for (b in seq(0.01, 1, 0.01)){  

    df$exp_x = exp(- a * df$X)
    df$exp_y = exp(- b *df$Y)

    ols = lm(data = df, formula =  Z ~ exp_x + exp_y)
    r_squared = summary(ols)$r.squared

    if (r_squared > best_rsquared){
      best_rsquared = r_squared 
      a_hat = a
      b_hat = b
      best_ols = ols
    }    
  }
}

a_hat 
b_hat 
best_ols
best_rsquared 

> a_hat 
[1] 0.34
> b_hat 
[1] 0.63
> best_ols

Call:
lm(formula = Z ~ exp_x + exp_y, data = df)

Coefficients:
(Intercept)        exp_x        exp_y  
     0.0686       2.0550       5.1189  

> best_rsquared
[1] 0.9898669

Problem: this is slow

It takes around 10 secs and I need to do it thousands times on others data frame.

How could I drastically speed it up?

Ricol
  • 377
  • 4
  • 9
  • 22

1 Answers1

5

Perhaps use nls instead. Since you did not set.seed(), cannot see whether our predictions would be similar, but at least I got the a and b estimates "right" after the edit:

nmod <- nls( Z ~ A*exp(-a*X)+B*exp(-b*Y), data=df, start=list(A=0.5, B=0.5, a=.1,b=.1))

> coef(nmod)
        A         B         a         b 
2.0005670 4.9541553 0.2951589 0.5937909 
#--------
> nmod
Nonlinear regression model
  model: Z ~ A * exp(-a * X) + B * exp(-b * Y)
   data: df
     A      B      a      b 
2.0006 4.9542 0.2952 0.5938 
 residual sum-of-squares: 0.9114

Number of iterations to convergence: 9 
Achieved convergence tolerance: 5.394e-06

Much faster than your 10 second experience. And this is on an 8 year-old machine.

> system.time( nmod <- nls( Z ~ A*exp(-a*X)+B*exp(-b*Y), data=df, start=list(A=0.5, B=0.5, a=.1,b=.1)) )
   user  system elapsed 
  0.036   0.002   0.033 
IRTFM
  • 258,963
  • 21
  • 364
  • 487