尝试在带有条件的函数上使用R和nls拟合数据

时间:2014-11-26 04:00:24

标签: r nls

我正在尝试将一些数据放入一个有效限制的函数中。更确切地说,如果t <= T且t> T,则具有不同值的函数。

以下是我尝试的代码:

posExpDecay <- function(t,tau,max,toff){ 1+max*(1-exp(-(t-toff)/tau)) } 
negExpDecay <- function(t,tau,max){ 1+max*exp(-(t)/tau) } 

data<-structure(list(t = c(0.67, 1, 1.33, 1.67, 2, 4, 6, 8, 10), y = c(1.02,2.33, 3.08, 3.34, 3.41,2.50, 1.86, 1.44, 1.22)), .Names = c("t", "y"), row.names = c(13L, 17L, 21L, 25L, 29L,37L, 45L, 49L, 53L), class = "data.frame")

fit <- nls(y~ifelse(t<=tswitch,
                    posExpDecay(t,tau1,max1,toff),
                    negExpDecay(t,tau2,max2)),
                  data,
                  start=list(max1=3,tau1=0.7,max2=7,tau2=2,toff=0.1,tswitch=3))

我收到以下错误:

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

这是我的起始参数还不够好(我尝过几次),我的问题在R中没有很好地翻译,或者我错过了一个基本的数学错误?

1 个答案:

答案 0 :(得分:4)

nls(...)默认使用高斯牛顿法;实际上很常见的错误信息意味着雅可比矩阵不能被反转。

我认为你的问题与你的复合函数(公式的RHS)在t=tswitch对于其他参数的任意值不连续的事实有关。换句话说,函数是连续的要求会对其他参数施加约束 - 它们不是彼此独立的。此外,复合函数的导数永远不会在t=tswitch处连续 - 您的posExpDecay(...)具有所有t的正导数,而您的negExpDecay(...)具有所有的负导数t

我不知道这种功能形式是否存在理论上的原因,但这些+/-指数通常使用正负衰减的产品进行建模,如下所示。 / p>

注意:我通常在nlsLM(...)包中使用minpack.lm,它使用更强大的Levenberg Marquardt算法。它与基础R中的nls(...)函数具有相同的签名。

f <- function(t, max,tau1,tau2,toff) max*exp(-t/tau1)*(1-exp(-(t-toff)/tau2))
library(minpack.lm)
fit <- nlsLM(y~f(t,max,tau1,tau2,toff),data,
             start=list(max=15,tau1=0.7,tau2=2,toff=.2))
summary(fit)
# ...
# Parameters:
#      Estimate Std. Error t value Pr(>|t|)    
# max   4.72907    0.29722  15.911 1.78e-05 ***
# tau1  6.75926    0.54093  12.496 5.82e-05 ***
# tau2  0.51211    0.08209   6.238  0.00155 ** 
# toff  0.53595    0.02667  20.093 5.64e-06 ***
# ---
# Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# 
# Residual standard error: 0.113 on 5 degrees of freedom
# 
# Number of iterations to convergence: 19 
# Achieved convergence tolerance: 1.49e-08

plot(y~t,data)
curve(predict(fit,data.frame(t=x)),add=T,col="blue")

正如您所看到的,这个更简单的功能(更少的参数)非常合适。