无法使用非线性拟合方法(nlsLM、nlxb 和 wrapnls)进行拟合

Failing to do fitting with non linear fitting methods (nlsLM, nlxb and wrapnls)

我有一个 nls fitting 任务想用 R 完成。 我第一次尝试这样做 here 正如@Roland 指出的

"The point is that complex models are difficult to fit. The more so, the less the data supports the model until it become impossible. You might be able to fit this, if you had extremely good starting values."

我同意@Roland 但如果 excel 可以做到这一点为什么 R 不能做到?

基本上这个拟合可以用Excel的GRG Nonlinear solver来完成,但是这个过程非常耗时,而且有时拟合不好。 (因为现实中有很多数据)

这是我的样本 data.frame。我想将每个 set 组与下面提供的模型相匹配,

set.seed(12345)
    set =rep(rep(c("1","2","3","4"),each=21),times=1)
    time=rep(c(10,seq(100,900,100),seq(1000,10000,1000),20000),times=1)
    value <- replicate(1,c(replicate(4,sort(10^runif(21,-6,-3),decreasing=FALSE))))
    data_rep <- data.frame(time, value,set)

     > head(data_rep)
            #    time        value set
            #1     10 1.007882e-06   1
            #2    100 1.269423e-06   1
            #3    200 2.864973e-06   1
            #4    300 3.155843e-06   1
            #5    400 3.442633e-06   1
            #6    500 9.446831e-06   1
            *      *       *         *

尝试 1

我已经 post 在这里提问 trouble-when-adding-3rd-fitting-parameter-in-nls

基本上问题是我想对分组数据进行拟合并根据拟合系数进行预测。

我使用了 library(minpack.lm) 中的 nlsLM 我得到了一个错误

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

根据@Roland 的说法,乍一看可能是模型错误或我的起始值不好。另一方面,我可以只用两个拟合参数来拟合这个模型。当我想将 third 参数添加到拟合函数时,问题就出现了。

尝试 2

其中 post trouble-when-adding-3rd-fitting-parameter-in-nls 通过关注@G。 Grothendieck 建议,我尝试了 nlmrt 包中的 nlxb 并将参数之一 d 固定为 d=32 并按如下方式进行拟合;

formula = value~Ps*(1-exp(-2*f*time*exp(-d)))*1/(sqrt(2*pi*sigma))*exp(-(d-d_ave)^2/(2*sigma))*d_step

d_step <- 1
f <- 1e9
d <- 32    
library(plyr)
library(nlmrt)
get.coefs <- function(data_rep) {
fit <-  nlxb(formula ,
              data = data_rep,
              start=c(d_ave=44,sigma=12,Ps=0.5),
              lower=c(d_ave=25,sigma=2,Ps=0.5),
              upper=c(d_ave=60,sigma=15,Ps=1),
              trace=TRUE)
}

fit <- dlply(data_rep, c("set"), .fun = get.coefs)   # Fit data grouped by "set"

#    > fit
#    $`1`
#    nlmrt class object: x 
#    residual sumsquares =  1.474e-07  on  21 observations
#        after  12    Jacobian and  13 function evaluations
#      name            coeff          SE       tstat      pval      #gradient    JSingval   
#    d_ave            42.0126            NA         NA         NA  #-7.082e-15    0.001733  
#    sigma            12.8377            NA         NA         NA   #2.408e-15   1.289e-19  
#    Ps              0.973223            NA         NA         NA    #9.33e-15    3.37e-20  
#    
#    $`2`
#    nlmrt class object: x 
#    residual sumsquares =  6.2664e-08  on  21 observations
#        after  12    Jacobian and  13 function evaluations
#      name            coeff          SE       tstat      pval      #gradient    JSingval   
#    d_ave             42.246            NA         NA         NA  #-7.269e-15    0.001428  
#    sigma            12.7429            NA         NA         NA   #2.568e-15   3.098e-19  
#    Ps              0.981517            NA         NA         NA   #9.211e-15   2.746e-20  
#    
#    $`3`
#    nlmrt class object: x 
#    residual sumsquares =  1.773e-07  on  21 observations
#        after  12    Jacobian and  13 function evaluations
#      name            coeff          SE       tstat      pval      #gradient    JSingval   
#    d_ave             41.968            NA         NA         NA  #-6.438e-15    0.001798  
#    sigma            12.8561            NA         NA         NA   #2.173e-15   2.414e-19  
#    Ps              0.972988            NA         NA         NA   #8.534e-15   5.922e-20  

#    $`4`
#    nlmrt class object: x 
#    residual sumsquares =  2.5219e-07  on  21 observations
#        after  12    Jacobian and  13 function evaluations
#      name            coeff          SE       tstat      pval      #gradient    JSingval   
#    d_ave            41.8532            NA         NA         NA  #-4.454e-15    0.001976  
#    sigma            12.9045            NA         NA         NA   #1.474e-15   3.443e-19  
#    Ps              0.974319            NA         NA         NA   #5.987e-15   3.124e-20  

#    attr(,"split_type")
#    [1] "data.frame"
#    attr(,"split_labels")
#      set
#    1   1
#    2   2
#    3   3
#    4   4

拟合系数合理 wolaa!但是这次我意识到(@G.Grothendieck 后来也指出了)nlxb 之后不可能预测新的值(为什么=?我不知道!)

predvals <- ldply(fit, .fun=predictvals, xvar="time", yvar="value",xrange=range(range)) # predict values 

::您可以从 here

中找到 predictvals 函数

Error in UseMethod("predict") : no applicable method for 'predict' applied to an object of class "nlmrt"

没有! coefpredict methods 用于 "nlmrt" class 个对象。

尝试 3

关注@G后。格洛腾迪克的另一个建议 接下来我尝试从 nlmrt.

wrapnls

因为在这篇post中他说, can-we-make-prediction-with-nlxb-from-nlmrt-package

”因为 nlmrt 包确实提供了 wrapnls 它将 运行 nlmrt 然后是 nls 这样一个 "nls" 对象结果然后该对象可以与所有 "nls" class 方法一起使用。

来自同一个 nlmrt 包仍然有如下问题

我在第一个 post 后放弃使用 plyr,因为加载 plyrdplyr 使我的问题更加复杂。所以我会坚持使用 dplyr 并改用 do 函数。

library(dplyr)
library(nlmrt)
formula = value~Ps*(1-exp(-2*f*time*exp(-d)))*1/(sqrt(2*pi*sigma))*exp(-(d-d_ave)^2/(2*sigma))*d_step

d_step <- 1
f <- 1e9
d <- 32

dffit = data_rep %>% group_by(set) %>%
  do(fit = wrapnls(formula ,
                data = .,
                start=c(d_ave=44,sigma=12,Ps=0.5),
                lower=c(d_ave=25,sigma=2,Ps=0.5),
                upper=c(d_ave=60,sigma=15,Ps=1),
                trace=TRUE))

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

我回到了开始的地方,出现了这个错误。 我想我已经尽我所能,寻找相关示例(尽管只有 3 个),阅读书籍并遵循建议。

像这样在 nlxb 之后使用 nls2 包中的 nls2(假设 data_repformulad_stepfd 来自问题)。为了使示例最小化,我们删除了 dplyr 并仅显示 set == 2.

的计算
library(nlmrt)
library(nls2)

data_rep2 <- subset(data_rep, set == 2)

fit.nlxb <- nlxb(formula , data = data_rep2,
                start = c(d_ave = 44, sigma = 12, Ps = 0.5),
                lower = c(d_ave = 25, sigma = 2, Ps = 0.5),
                upper = c(d_ave = 60, sigma = 15, Ps = 1))

fit.nls <- nls2(formula, data = data_rep2, start = fit.nlxb$coefficients,
  algorithm = "brute-force")

identical(fit.nlxb$coefficients, coef(fit.nls))
## [1] TRUE

fit.nls 是一个 "nls" class 对象,其系数与 fit.nlxb 相同,我们可以使用 fitted()predict() 以及所有其他 "nls" 方法。