我想在R中使用等温模型得到以下数据。最简单的等温模型是Langmuir模型,这里给出model is given in the bottom of the page。我的MWE在下面给出了抛出错误。我想知道Isotherm模型是否有任何R包。
X <- c(10, 30, 50, 70, 100, 125)
Y <- c(155, 250, 270, 330, 320, 323)
Data <- data.frame(X, Y)
LangIMfm2 <- nls(formula = Y ~ Q*b*X/(1+b*X), data = Data, start = list(Q = 1, b = 0.5), algorith = "port")
Error in nls(formula = Y ~ Q * b * X/(1 + b * X), data = Data, start = list(Q = 1, :
Convergence failure: singular convergence (7)
被修改
一些非线性模型可以转换为线性模型。我的理解是,非线性模型的估计与其线性模型形式之间可能存在一对一的关系,但它们相应的标准误差彼此无关。这个断言是真的吗?通过转换为线性来拟合非线性模型是否存在任何缺陷?
答案 0 :(得分:3)
我不知道这样的软件包,我个人认为你不需要一个,因为问题可以通过基础R来解决。
nls
对起始参数很敏感,所以你应该从良好的开始猜测开始。您可以轻松评估Q
,因为它对应于x - > Inf的等温线的渐近极限,因此从Q=323
开始是合理的(这是{{1}的最后一个值在您的示例数据集中)。
接下来,您可以执行Y
并添加一行,其中包含与您的起始参数plot(Data)
和Q
以及调整b
相对应的等温线,以便找到合理的猜测。
下图显示了您的数据集(点)和探针等温线,Q = 323和b = 0.5,由b
(红线)生成。对我来说这似乎是一个合理的开始猜测,我尝试了with(Data,lines(X,323*0.5*X/(1+0.5*X),col='red'))
:
nls
并绘制预测线以确保LangIMfm2 <- nls(formula = Y ~ Q*b*X/(1+b*X), data = Data, start = list(Q = 300, b = 1), algorith = "port")
# Nonlinear regression model
# model: Y ~ Q * b * X/(1 + b * X)
# data: Data
# Q b
# 366.2778 0.0721
# residual sum-of-squares: 920.6
#
# Algorithm "port", convergence message: relative convergence (4)
找到正确的解决方案:
nls
话虽如此,我建议使用更有效的策略,基于模型的线性化,通过在倒数坐标中重写等温线方程:
lines(Data$X,predict(LangIMfm2),col='green')
正如您所看到的,两种方法产生的结果基本相同,但线性模型更稳健,不需要启动参数(据我记得,它是等温线分析的标准方法。实验物理化学。)
答案 1 :(得分:0)
您可以在nlme软件包中为R使用SSmicmen自启动函数(请参阅Ritz和Streibig,2008,带有R的非线性回归),该函数根据Michaelis-Menten(MM)的线性化形式的拟合来计算初始参数)方程式。幸运的是,MM方程具有可用于Langmuir方程的形式S = Smax * x /(KL + x)。我发现nlshelper和tidyverse软件包可用于对nls命令的结果进行建模并将其导出到表和图中,特别是在对样本组进行建模时。这是我的用于模拟一组吸附数据的代码:
{
Hello: [[2001, 51], [2003, 52], [2002, 90]]
Jello: [[2009, 22], [2003, 4], [2002, 11]]
Cello: [[2001, 16]]
}
library(tidyverse)
library(nlme)
library(nlshelper)
为简单起见,此处将Langmuir亲和常数建模为1 / KL。应用此代码,我得到的参数估计与上面给出的@Marat相同。
下面的简单代码允许对数据进行整理,以创建一个包含原始点和拟合线的ggplot对象(即geom_point代表原始X和Y数据,geom_line代表原始X和YHat)。
lang.fit <- nls(Y ~ SSmicmen(X,Smax,InvKL), data=Data)
fit.summary <- tidy(lang.fit)
fit.coefs <- coef(lang.fit)
如果要建模多组数据(例如,基于“ Sample_name”列,则将使用nlsList命令,如下所示计算lang.fit变量:
FitY <- tibble(predict(lang.fit))
YHat <- FitY[,1]
Data2 <- cbind(Data, YHat)
答案 2 :(得分:0)
问题是起始值。我们展示了两种解决方法,以及使用问题中的起始值也可以收敛的另一种方法。
1)plinear 右手边在Q * b中是线性的,因此最好将b吸收到Q中,然后我们有一个线性输入的参数,因此更容易求解。同样,对于plinear算法,线性参数不需要起始值,因此仅需要指定b的起始值。对于plinear,应将nls公式的右侧指定为与线性参数相乘的向量。运行nls在下面给出fm0
的结果将是名为b
和.lin
的系数,其中Q = .lin / b。
我们已经从fm0
得到了答案,但是如果我们希望以b
和Q
而不是b
和.lin
的方式进行清洁测试,我们可以如图所示,使用fm0
返回的系数所隐含的起始值来运行问题中的原始公式。
fm0 <- nls(Y ~ X/(1+b*X), Data, start = list(b = 0.5), alg = "plinear")
st <- with(as.list(coef(fm0)), list(b = b, Q = .lin/b))
fm <- nls(Y ~ Q*b*X/(1+b*X), Data, start = st)
fm
给予
Nonlinear regression model
model: Y ~ Q * b * X/(1 + b * X)
data: Data
b Q
0.0721 366.2778
residual sum-of-squares: 920.6
Number of iterations to convergence: 0
Achieved convergence tolerance: 9.611e-07
我们可以显示结果。点是数据,红线是拟合曲线。
plot(Data)
lines(fitted(fm) ~ X, Data, col = "red")
2)均值或者,对于Q使用均值(Data $ Y)的起始值似乎效果很好。
nls(Y ~ Q*b*X/(1+b*X), Data, start = list(b = 0.5, Q = mean(Data$Y)))
给予:
Nonlinear regression model
model: Y ~ Q * b * X/(1 + b * X)
data: Data
b Q
0.0721 366.2779
residual sum-of-squares: 920.6
Number of iterations to convergence: 6
Achieved convergence tolerance: 5.818e-06
该问题对于我们使用的b
已经具有一个合理的起始值,但是如果需要,可以将Y
设置为Q*b
以便将其取消,将X
设置为均值(Data $ X)并求解b
以给出b = 1 - 1/mean(Data$X)
作为可能的起始值。尽管未显示使用b
的起始值和mean(Data$Y)
作为Q
的起始值,也会导致收敛。
3)优化如果我们使用optim
,则算法甚至会收敛于问题中使用的初始值。我们形成残差平方和并将其最小化:
rss <- function(p) {
Q <- p[1]
b <- p[2]
with(Data, sum((Y - b*Q*X/(1+b*X))^2))
}
optim(c(1, 0.5), rss)
给予:
$par
[1] 366.27028219 0.07213613
$value
[1] 920.62
$counts
function gradient
249 NA
$convergence
[1] 0
$message
NULL