nls 中二进制运算符错误的非数字参数

non-numeric argument to binary operator error in nls

我正在尝试 运行 以下代码,但它给了我:

Error in qr.default(.swts * attr(rhs, "gradient")) : NA/NaN/Inf in foreign function call (arg 1) In addition: Warning message: In log(.expr4) : NaNs produced

你能帮我一下吗?谢谢!

model <- deriv( ~ c*(1+b*(q-1)*t)^(1/(1-q)),  c("c", "b", "q"), function (t, c, b,q){})

nls(Frequency ~ model(t, c, b, q), data=DF,start=list(c = 1, b = 1.5, q =0.5))

您可以在下面看到一部分数据,正如我在上面解释的那样,我正在尝试为其拟合 q 指数分布函数。 我在 R 中使用 uiung nls 函数来获取给定数据的估计值(q 指数)。

t 频率 0 195746 1 93938 2 53181 3 31853 4 19856 5 12182 6 7847 7 5459 8 4325 9 3203 10 2750

tl;dr 你需要更加努力地思考 about/find 合理的起始值。

设置数据和模型:

 dd <- data.frame(t=0:10,
            Frequency=c(195746,93938,53181,31853,19856,12182,
                        7847,5459,4325,3203,2750))
model <- deriv( ~ c*(1+b*(q-1)*t)^(1/(1-q)),
               c("c", "b", "q"), function (t, c, b,q){})

如果您只是在初始参数处计算 model(),您会看到关于 q 的一些导数是 NaN(它总是 值得尝试在起始值处评估 objective 函数和梯度以确保它们有意义)。除此之外,如果您查看 objective 函数的值,您会发现它们与数据相去甚远(它们从 1 增加到 42,而数据从 200000 减少到 3000 ... )

par0 <- list(c = 1, b = 1.5, q =0.5)
with(par0,model(dd$t,c,b,q))
##  [1]  1.0000  0.0625  0.2500  1.5625  4.0000  7.5625 12.2500 18.0625 25.0000
## [10] 33.0625 42.2500
## attr(,"gradient")
##             c     b         q
##  [1,]  1.0000  0.00 0.0000000
##  [2,]  0.0625 -0.25 0.4034264
##  [3,]  0.2500  1.00       NaN
##  [4,]  1.5625  3.75       NaN
...

问题是将负值提高到分数次幂会得到 NaN。当 q <1 时,当 t 足够大时基数将变为负数 ...

with(par1,model(dd$t,c,b,q))

我尝试设置q=0(使指数的底值为1),但仍然遇到同样的问题。

如果我们从 q-1 大于 0 的值开始,这样基数就会是正数怎么办?

par2 <- list(c = 1, b = 1.5, q =2)
nls(Frequency ~ model(t, c, b, q), data=dd,start=par2)

Error in nls(Frequency ~ model(t, c, b, q), data = dd, start = par2) : step factor 0.000488281 reduced below 'minFactor' of 0.000976562

好的,情况有所好转,但仍然失败。如果我们尝试从更合理的规模开始,即将 c 设置为 100000 会怎样?

par3 <- list(c = 1e5, b = 1.5, q =2)
fit3 <- nls(Frequency ~ model(t, c, b, q), data=dd,start=par3)

绘图结果:

par(las=1,bty="l")
plot(Frequency/1000~t,data=dd)
newdat <- data.frame(t=seq(0,10,length=51))
lines(newdat$t,predict(fit3,newdata=newdat)/1000)