Search code examples
rregressioncurve-fittingdata-fittingnls

2 curves simultaneous nonlinear regression


I'm trying to fit two curves using nlm but I'm having some problems. First I've tried to fit each curve separately, and all it's ok and the parameters obtained are similar than the parameters used to simulate the curves.

Each curve is defined by a different equations, but they share some parameters. So, I wonder if it is possible to fit simultaneously both curves using nlm or others optimization methods.

x<-seq(0,120, by=5)
y<-100/50*exp(-0.02*x)*rnorm(25, mean=1, sd=0.05)
y2<-(1*100/50)*(0.1/(0.1-0.02))*(exp(-0.02*x)-exp(-0.1*x))*rnorm(25, mean=1, sd=0.05)
xy<-data.frame(x,y)
xy2<-data.frame(x,y2)
fit<-nls(y~100/a*exp(-b*x), data=xy, start=c(a=45, b=0.018), trace=T)

fit

# Nonlinear regression model
#  model: y ~ 100/a * exp(-b * x)
#   data: xy
#       a        b 
# 51.68688  0.01936 
# residual sum-of-squares: 0.01934
#
# Number of iterations to convergence: 4 
# Achieved convergence tolerance: 1.395e-07

fit2<-nls(y2~100/a*(c/(c-b))*(exp(-b*x)-exp(-c*x)), data=xy2, 
    start=c(a=45, b=0.018, c=0.15), trace=T)

fit2

# Nonlinear regression model
#  model: y2 ~ 100/a * (c/(c - b)) * (exp(-b * x) - exp(-c * x))
#   data: xy2
#        a        b        c 
# 49.92938  0.01997  0.09903 
# residual sum-of-squares: 0.03024
#
# Number of iterations to convergence: 4 
# Achieved convergence tolerance: 2.12e-06

Solution

  • Here's one way to do it. (On edit: this works fine, a typo in my original code made it seem like it wasn't working, thanks to @MrFlick and @Gregor for pointing this out). First replicate your code with a fixed random seed:

    set.seed(1)
    x<-seq(0,120, by=5)
    y<-100/50*exp(-0.02*x)*rnorm(25, mean=1, sd=0.05)
    y2<-(1*100/50)*(0.1/(0.1-0.02))*(exp(-0.02*x)-exp(-0.1*x))*rnorm(25, mean=1, sd=0.05)
    xy<-data.frame(x,y)
    xy2<-data.frame(x,y2)
    
    fit<-nls(y~100/a*exp(-b*x), data=xy, start=c(a=45, b=0.018))
    fit
    #     Nonlinear regression model
    #   model: y ~ 100/a * exp(-b * x)
    #    data: xy
    #        a        b 
    # 50.29461  0.01962 
    #  residual sum-of-squares: 0.0362
    
    # Number of iterations to convergence: 4 
    # Achieved convergence tolerance: 1.719e-07
    
    
    fit2<-nls(y2~100/a*(c/(c-b))*(exp(-b*x)-exp(-c*x)), data=xy2, start=c(a=45, b=0.018, c=0.15))
    fit2
    # Nonlinear regression model
    #   model: y2 ~ 100/a * (c/(c - b)) * (exp(-b * x) - exp(-c * x))
    #    data: xy2
    #        a        b        c 
    # 49.26033  0.02041  0.09455 
    #  residual sum-of-squares: 0.02364
    #
    # Number of iterations to convergence: 5 
    # Achieved convergence tolerance: 8.4e-06
    

    Now to combine them:

    xy0<-data.frame(x=c(x,x),y=c(y,y2),isY1=c(rep(c(1,0),each=length(x))),
                    isY2=c(rep(c(0,1),each=length(x))))
    fit0<-nls(y~isY1*(100/a*exp(-b*x))+isY2*(100/a*(c/(c-b))*(exp(-b*x)-exp(-c*x))), data=xy0, start=c(a=45, b=0.018,c=0.15))
    
    
    fit0
    # Nonlinear regression model
    #   model: y ~ isY1 * (100/a * exp(-b * x)) + isY2 * (100/a * (c/(c - b)) *     (exp(-b * x) - exp(-c * x)))
    #    data: xy0
    #        a        b        c 
    # 50.19176  0.01978  0.09800 
    #  residual sum-of-squares: 0.06114
    
    # Number of iterations to convergence: 5 
    # Achieved convergence tolerance: 1.005e-06