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)