2015-11-29 24 views
0

拟合参数的任意数量的非线性最小二乘欲拟合模型,其包括在可变数量的系数的总和,如这里与R中

Model

我想编写代码,以便在运行拟合程序时(即将i设置为任何正整数值),潜在用户可以指定系数的数量,但是我不知道如何开始编码。当然,我可以简单地写出大量潜在变量的结果方程式(例如,对于 i ),并在开始时切换到指定的一个,但我更喜欢“漂亮”的解决方案(即是更少的线),如果在R所有可用我目前正在使用nls,但我当然会很满意任何解决方案。

这是我试过到目前为止:

Model <- function(X0, t, X, tau){X0+((X*tau*(exp(1/tau)-1))*exp(-t/tau))} 

set.seed(1) 
df <- data.frame(t=sort(sample(1:100,50))) 
df$P <- jitter(with(df, Model(X0=0.1, t=t, X=0.2, tau=5)), 1000) 

Model_fit <- nls(P ~ Model(X0=0.1, t=t, X=X1_fit, tau=5) 
        , start = list(X1_fit=c(0.1)), data=df, trace = F) 

plot(df$t,df$P) 
lines(df$t, predict(Model_fit, list(P = df$P))) 

它工作得很好。只需将一个矢量传递给X1_fit即可适合多个系数也很容易。然而,我现在正在努力的是如何正确地在公式中形成总和。我不能只用

X=c(0.2,5) 
Model <- function(X0, t, X, tau){X0+sum((X*tau*(exp(1/tau)-1))*exp(-t/tau))} 

,因为这当然是返回一个值,即在t的依赖会丢失。相反,代码只需要为每个单独的值t取总和,以便该函数仍返回长度为t的向量。然而,我正在努力弄清楚如何做到这一点,而不会恢复到循环,这可能也很难适合通过nls?

干杯!

编辑

@G。格洛腾迪克的答案很好,但我意识到拟合过程对方程中的微小修改非常敏感,特别是当不止一个常数需要拟合时。例如

set.seed(1) 
Model <- function(X0, t, X, tau) { 
    res <- X0 + rowSums(sapply(seq_along(X), function(i) 
(X[i]*tau[i]/5*(exp(5/tau[i])-1))*exp(-t/tau[i])))} 

df <- data.frame(t=sort(sample(1:100,50))) 
df$P <- jitter(with(df, Model(X0=0.1, t=t, X=c(0.2, 2), tau=c(4, 7))),  1000) 

Model_fit <- nls(P ~ Model(X0=0.1, t=t, X=X1_fit, tau=tau_fit) 
      , start = list(X1_fit=c(0.1, 1), tau_fit=5:6), data=df) 

不运行

Error in nls(P ~ Model(X0 = 0.1, t = t, X = X1_fit, tau = tau_fit), start = list(X1_fit = c(0.1, : 
    step factor 0.000488281 reduced below 'minFactor' of 0.000976562 

(我在两个地方加一个常数5,现在也尽量适应tau),降低了步长,增加的数量甚至当迭代。原则上,我认识到拟合4个系数很容易变得不稳定,但是我在Matlab中选择的代码似乎处理得很好(甚至更合适的系数)。也许这个问题在单独的问题中会更好,但是当线程提到“任意数量的拟合参数”时,我觉得这个后续处理最好是作为编辑来完成。

+0

我添加了一个最小代码示例。 – David

回答

1

sapply对i创建2D矩阵,并使用rowSums执行求和:

set.seed(1) 
Model <- function(X0, t, X, tau) { 
    res <- X0 + rowSums(sapply(seq_along(X), function(i) 
    (X[i]*tau[i]*(exp(1/tau[i])-1))*exp(-t/tau[i]))) 
} 

df <- data.frame(t=sort(sample(1:100,50))) 
df$P <- jitter(with(df, Model(X0=0.1, t=t, X=c(0.2, 2), tau=c(4, 7))), 1000) 



Model_fit <- nls(P ~ Model(X0=0.1, t=t, X=X1_fit, tau=5:6) 
        , start = list(X1_fit=c(0.1, 1)), data=df, trace = F) 

plot(df) 
lines(fitted(Model_fit) ~ t, df, col = "red") 

给予:

> Model_fit 
Nonlinear regression model 
    model: P ~ Model(X0 = 0.1, t = t, X = X1_fit, tau = 5:6) 
    data: df 
X1_fit1 X1_fit2 
0.2107 2.0849 
residual sum-of-squares: 0.5175 

Number of iterations to convergence: 1 
Achieved convergence tolerance: 1.511e-07 

screenshot