R中的指数曲线拟合

2024-03-08

time = 1:100  
head(y)  
0.07841589 0.07686316 0.07534116 0.07384931 0.07238699 0.07095363   
plot(time,y)  

这是一条指数曲线。

  1. 在不知道公式的情况下如何在这条曲线上拟合直线?我不能使用“nls”,因为公式未知(仅给出数据点)。

  2. 我怎样才能得到这条曲线的方程并确定方程中的常数?
    我尝试了黄土,但它没有给出截距。


You need a model to fit to the data. Without knowing the full details of your model, let's say that this is an exponential growth model https://en.wikipedia.org/wiki/Exponential_growth, which one could write as: y = a * e r*t

Where y是你的测量变量,t是测量的时间,a是 y 时的值t = 0 and r是增长常数。 我们想要估计a and r.

这是一个非线性问题,因为我们想要估计指数,r。 然而,在这种情况下,我们可以使用一些代数,通过两边取对数并求解,将其转换为线性方程(记住对数规则 https://www.chilimath.com/lessons/advanced-algebra/logarithm-rules/), 导致:log(y) = log(a) + r * t

我们可以通过一个例子来可视化这一点,通过从我们的模型生成一条曲线,假设一些值a and r:

t <- 1:100      # these are your time points
a <- 10         # assume the size at t = 0 is 10
r <- 0.1        # assume a growth constant
y <- a*exp(r*t) # generate some y observations from our exponential model

# visualise
par(mfrow = c(1, 2))
plot(t, y)      # on the original scale
plot(t, log(y)) # taking the log(y)

因此,对于这种情况,我们可以探索以下可能性:

  • 将我们的非线性模型拟合到原始数据(例如使用nls()功能)
  • 将我们的“线性化”模型拟合到对数转换数据(例如使用lm()功能)

选择哪个选项(还有更多选项),取决于我们的想法 (或假设)是我们数据背后的数据生成过程。

让我们用一些包含添加噪声的模拟来说明(采样自 正态分布),以模拟真实数据。请看这个StackExchange 帖子 https://stats.stackexchange.com/questions/61747/linear-vs-nonlinear-regression?rq=1对于这个模拟背后的推理(由阿莱霍·伯纳丁的评论 https://stackoverflow.com/questions/31851936/exponential-curve-fitting-in-r/31854405#comment81629348_31854405).

set.seed(12) # for reproducible results

# errors constant across time - additive
y_add <- a*exp(r*t) + rnorm(length(t), sd = 5000) # or: rnorm(length(t), mean = a*exp(r*t), sd = 5000)

# errors grow as y grows - multiplicative (constant on the log-scale)
y_mult <- a*exp(r*t + rnorm(length(t), sd = 1))  # or: rlnorm(length(t), mean = log(a) + r*t, sd = 1)

# visualise
par(mfrow = c(1, 2))
plot(t, y_add, main = "additive error")
lines(t, a*exp(t*r), col = "red") 
plot(t, y_mult, main = "multiplicative error")
lines(t, a*exp(t*r), col = "red")

对于加性模型,我们可以使用nls(),因为误差在整个过程中是恒定的t。使用时nls()我们需要为优化算法指定一些起始值(尝试“猜测”这些是什么,因为nls()经常难以集中于解决方案)。

add_nls <- nls(y_add ~ a*exp(r*t), 
               start = list(a = 0.5, r = 0.2))
coef(add_nls)

#           a           r 
# 11.30876845  0.09867135 

使用coef()函数我们可以得到两个参数的估计值。 这为我们提供了良好的估计,接近我们的模拟(a = 10 和 r = 0.1)。

通过绘制模型的残差,您可以看到误差方差在数据范围内相当恒定:

plot(t, resid(add_nls))
abline(h = 0, lty = 2)

对于乘法误差情况(我们的y_mult模拟值),我们应该使用lm()在对数转换的数据上,因为 相反,误差在该范围内是恒定的。

mult_lm <- lm(log(y_mult) ~ t)
coef(mult_lm)

# (Intercept)           t 
#  2.39448488  0.09837215 

为了解释这个输出,再次记住我们的线性化模型是log(y) = log(a) + r*t,相当于以下形式的线性模型Y = β0 + β1 * X, where β0是我们的截距β1我们的斜坡。

因此,在此输出中(Intercept)相当于log(a)我们的模型和t是时间变量的系数,所以相当于我们的r。 有意义地解释(Intercept)我们可以取它的指数(exp(2.39448488)),给我们~10.96,这非常接近我们的模拟值。

值得注意的是,如果我们拟合误差为乘法的数据,会发生什么 使用nls函数代替:

mult_nls <- nls(y_mult ~ a*exp(r*t), start = list(a = 0.5, r = 0.2))
coef(mult_nls)

#            a            r 
# 281.06913343   0.06955642 

现在我们高估了a并低估r (马里奥路特 https://stackoverflow.com/questions/31851936/exponential-curve-fitting-in-r/31854405#comment105713296_31854405在他的评论中强调了这一点)。我们可以想象使用错误的方法来拟合我们的模型的后果:

# get the model's coefficients
lm_coef <- coef(mult_lm)
nls_coef <- coef(mult_nls)

# make the plot
plot(t, y_mult)
lines(t, a*exp(r*t), col = "brown", lwd = 5)
lines(t, exp(lm_coef[1])*exp(lm_coef[2]*t), col = "dodgerblue", lwd = 2)
lines(t, nls_coef[1]*exp(nls_coef[2]*t), col = "orange2", lwd = 2)
legend("topleft", col = c("brown", "dodgerblue", "orange2"), 
       legend = c("known model", "nls fit", "lm fit"), lwd = 3)

我们可以看到如何lm()对数转换数据的拟合效果明显优于nls()拟合原始数据。

您可以再次绘制该模型的残差,以查看方差在数据范围内不是恒定的(我们也可以在上图中看到这一点,其中数据的分布随着t):

plot(t, resid(mult_nls))
abline(h = 0, lty = 2)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

R中的指数曲线拟合 的相关文章

随机推荐