使用 lm()
请阅读?formula 以获得正确的公式说明。现在我会继续假设你已经阅读了。
首先,您的模型在对 LHS 和 RHS 进行 log 变换后,变为:
log(y) = log(10000) + r * x
常数是一个已知值,不能估计。这样的常量在lm 中称为offset。
你应该像这样使用lm:
# "-1" in the formula will drop intercept
fit <- lm(log(y) ~ x - 1, data = df, offset = rep(log(10000), nrow(df)))
# Call:
# lm(formula = log(y) ~ x - 1, data = df, offset = rep(log(10000), nrow(df)))
# Coefficients:
# x
# 0.02618
如您所见,fit 是一个长度为 13 的列表。请参阅?lm 的“值”部分,您会更好地了解它们是什么。其中,拟合值为$fitted,因此您可以通过以下方式绘制图:
plot(df)
lines(df$x, exp(fit$fitted), col = 2, lwd = 2) ## red line
注意我使用exp(fit$fitted),因为我们为log(y) 拟合了一个模型,现在我们要回到原来的规模。
备注
正如@BenBolker 所说,一个更简单的规范是:
fit <- lm(log(y/10000) ~ x - 1, data = df)
或
fit <- lm(log(y) - log(10000) ~ x - 1, data = df)
但是现在响应变量不是log(y)而是log(y/10000),所以当你制作情节时,你需要:
lines(df$x, 10000 * exp(fit$fitted), col = 2, lwd = 2)
使用nls()
nls()的正确使用方式如下:
nls(y ~ 10000 * exp(r * x), data = df, start = list(r = 0.1))
因为非线性曲线拟合需要迭代,所以需要一个起始值,并且必须通过参数start提供。
现在,如果你试试这段代码,你会得到:
Error in nls(y ~ 10000 * exp(r * x), data = df, start = list(r = 0.1)) :
number of iterations exceeded maximum of 50
问题在于您的数据是准确的,没有噪音。阅读?nls:
Warning:
*Do not use ‘nls’ on artificial "zero-residual" data.*
因此,将nls() 用于您的玩具数据集df 是行不通的。
我们回去检查一下lm()的拟合模型:
fit$residuals
# 1 2 3 4 5
#-2.793991e-16 -1.145239e-16 -2.005405e-15 -5.498411e-16 3.094618e-15
# 6 7 8
# 1.410007e-15 -1.099682e-15 -1.007937e-15
残差在所有地方基本上都是 0,lm() 在这种情况下完全适合。
跟进
我无法弄清楚的最后一件事是为什么lm 的公式规范中没有使用参数r。
lm 和nls 之间的公式实际上存在一些差异。也许你可以这样理解:
-
lm() 的公式称为模型公式,可以从?formula 阅读。它在 R 中非常基础。模型拟合例程使用它,例如 lm、glm,而许多函数具有公式方法,例如 model.matrix、aggregate、boxplot 等。
-
nls() 的公式更像是一个函数规范,并没有被广泛使用。许多其他执行非线性迭代的函数,如optim,将不接受公式,而是直接接受函数。因此,只需将 nls() 视为特例即可。
那么使用线性模型是否有意义?我在这里尝试建模的只是使用马尔萨斯增长模型。
严格来说,给出真实的人口数据(当然有噪声),使用nls() 进行曲线拟合,或使用glm(, family = poisson) 进行泊松响应 GLM 比拟合线性模型具有更好的基础。 glm() 调用您的数据将是:
glm(y ~ x - 1, family = poisson(), data = df, offset = rep(log(10000), nrow(df)))
(您可能需要先了解 GLM 是什么。)但是由于您的数据没有噪音,因此您在使用时会收到警告消息。
但是,就计算复杂度而言,通过首先进行log 变换来使用线性模型是明显的胜利。在统计建模中,变量变换非常普遍,因此没有令人信服的理由拒绝使用线性模型来估计人口增长率。p>
总体而言,我建议您尝试所有三种方法来处理真实数据(或嘈杂的玩具数据)。估计和预测会有一些差异,但不会很大。
“后续跟进”
哈哈,再次感谢@Ben。对于glm(),我们也可以试试:
glm(y ~ x - 1 + offset(log(10000)), family = gaussian(link="log"))
对于offset 规范,我们可以在lm/glm 中使用offset 参数,或者像Ben 那样使用offset() 函数。