评估 R nls 中多个因素的渐近线
Evaluating asymptote in R nls for multiple factors
我正在尝试使用 R 中的 NLS 评估不同种群是否达到不同的渐近线。这里我有两个 data.frames df1 只有一个种群(由站点表示)
df1<- structure(list(Site = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("ALT01",
"ALT02", "ALT03", "Cotton", "Deep", "Eckhardt", "Green", "Johnson",
"Kissinger", "Marsh", "Sand", "Shypoke", "Sora", "Spike", "Tamora",
"WRP01", "WRP05", "WRP08", "WRP10", "WRP11", "WRP12", "WRP14",
"WRP15", "WRP18"), class = "factor"), Nets = 1:18, Cumulative.spp = c(12L,
13L, 15L, 17L, 17L, 17L, 17L, 19L, 19L, 19L, 19L, 20L, 22L, 22L,
22L, 22L, 22L, 22L)), .Names = c("Site", "Nets", "Cumulative.spp"
), row.names = c(NA, 18L), class = "data.frame")
并且 df2 必须人口(再次由站点表示)
df2 <- structure(list(Site = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L,
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("ALT01",
"ALT02", "ALT03", "Cotton", "Deep", "Eckhardt", "Green", "Johnson",
"Kissinger", "Marsh", "Sand", "Shypoke", "Sora", "Spike", "Tamora",
"WRP01", "WRP05", "WRP08", "WRP10", "WRP11", "WRP12", "WRP14",
"WRP15", "WRP18"), class = "factor"), Nets = c(1L, 2L, 3L, 4L,
5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,
1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L,
15L, 16L, 17L, 18L), Cumulative.spp = c(12L, 13L, 15L, 17L, 17L,
17L, 17L, 19L, 19L, 19L, 19L, 20L, 22L, 22L, 22L, 22L, 22L, 22L,
7L, 10L, 11L, 12L, 13L, 14L, 14L, 14L, 15L, 15L, 16L, 16L, 16L,
16L, 16L, 17L, 17L, 17L)), .Names = c("Site", "Nets", "Cumulative.spp"
), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L,
12L, 13L, 14L, 15L, 16L, 17L, 18L, 25L, 26L, 27L, 28L, 29L, 30L,
31L, 32L, 33L, 34L, 35L, 36L, 37L, 38L, 39L, 40L, 41L, 42L), class = "data.frame")
当我为一个人群建模时,一切看起来都很棒:
Model1<-nls(Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0), data = df1)
我想做的是看看我是否可以将多个群体添加到同一模型并添加一个站点变量,我试过这个:
Model2<-nls(Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0) + Site , data = df2)
还有这个:
Model2<-nls(Cumulative.spp ~ SSasympOff(Nets + Site , A, lrc, c0), data = df2)
但到目前为止运气不佳,我们将不胜感激。
我们假设您希望两个群体有不同的 Asym
参数,但有共同的 lrc
和 c0
参数。
首先在(1)中我们展示了如何修改问题中的解决方案以获得答案。 (1) 中的大部分代码只是为了获取起始值,但实际拟合只有一行代码——如果算上我们在单独的一行中定义公式这一事实,则为两行。
然后在 (2) 中,我们将展示如何通过使用算法 "plinear"
来简化 (1),从而无需获取线性参数的起始值。在 (2a) 中,我们展示了进一步的简化,它更容易扩展到更多站点,在 (2b) 中,我们在所有站点都存在的条件下进一步简化(问题中并非如此,但实际情况可能如此)数据)。
1) 默认算法 我们可以通过分别拟合每个群体 (fm1
, fm2
) 和一起拟合得到 nls
中的起始值(fm3
)。最后用不同的 Asym
参数拟合模型 (fm4
).
# get starting values
fo <- Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0)
fm1 <- nls(fo, df2, subset = Site == "ALT01")
fm2 <- nls(fo, df2, subset = Site == "ALT03")
fm3 <- nls(fo, df2)
st <- c(A1 = coef(fm1)[["A"]], A2 = coef(fm2)[["A"]], coef(fm3)[c("lrc", "c0")])
# fit
fo4 <- Cumulative.spp ~ SSasympOff(Nets, A1*(Site=="ALT01")+A2*(Site=="ALT03"), lrc, c0)
fm4 <- nls(fo4, data = df2, start = st)
plot(Cumulative.spp ~ Nets, df2, col = Site)
points(fitted(fm4) ~ Nets, df2, col = "red", pch = 20)
2) plinear 实际上 Asym
是特殊的,因为模型在其中是线性的,我们可以用它来简化上面的内容,因为我们不需要起始值对于线性参数,如果我们切换到 algorithm="plinear"
。这消除了 运行 fm1
和 fm2
的需要。我们只需要 fm3
来生成起始值。请注意,"plinear"
要求公式的 RHS 是一个矩阵,每一列乘以一个线性参数的系数。这里我们有两个线性参数(每个 Site
的 Asym
)所以它是一个双列矩阵。
# get starting values
fo <- Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0)
fm3 <- nls(fo, df2)
st5 <- coef(fm3)[c("lrc", "c0")]
# fit
mm <- with(df2, cbind(Site=="ALT01", Site=="ALT03"))
fo5 <- Cumulative.spp ~ mm * SSasympOff(Nets,1,lrc,c0)
fm5 <- nls(fo5, data = df2, start = st5, algorithm = "plinear")
2a) mm
也可以这样写,它的优点是可以扩展到更多站点:
mm <- model.matrix(~ Site - 1, transform(df2, Site = droplevels(Site)))
2b) 如果 Site
因子的所有级别都在数据中表示,那么我们可以进一步简化为 droplevels(Site)
(这会删除未使用的级别)然后可以简单地 Site
允许我们写:
mm <- model.matrix(~ Site - 1, df2)
更新: 一些修复和改进。
我正在尝试使用 R 中的 NLS 评估不同种群是否达到不同的渐近线。这里我有两个 data.frames df1 只有一个种群(由站点表示)
df1<- structure(list(Site = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("ALT01",
"ALT02", "ALT03", "Cotton", "Deep", "Eckhardt", "Green", "Johnson",
"Kissinger", "Marsh", "Sand", "Shypoke", "Sora", "Spike", "Tamora",
"WRP01", "WRP05", "WRP08", "WRP10", "WRP11", "WRP12", "WRP14",
"WRP15", "WRP18"), class = "factor"), Nets = 1:18, Cumulative.spp = c(12L,
13L, 15L, 17L, 17L, 17L, 17L, 19L, 19L, 19L, 19L, 20L, 22L, 22L,
22L, 22L, 22L, 22L)), .Names = c("Site", "Nets", "Cumulative.spp"
), row.names = c(NA, 18L), class = "data.frame")
并且 df2 必须人口(再次由站点表示)
df2 <- structure(list(Site = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L,
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("ALT01",
"ALT02", "ALT03", "Cotton", "Deep", "Eckhardt", "Green", "Johnson",
"Kissinger", "Marsh", "Sand", "Shypoke", "Sora", "Spike", "Tamora",
"WRP01", "WRP05", "WRP08", "WRP10", "WRP11", "WRP12", "WRP14",
"WRP15", "WRP18"), class = "factor"), Nets = c(1L, 2L, 3L, 4L,
5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,
1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L,
15L, 16L, 17L, 18L), Cumulative.spp = c(12L, 13L, 15L, 17L, 17L,
17L, 17L, 19L, 19L, 19L, 19L, 20L, 22L, 22L, 22L, 22L, 22L, 22L,
7L, 10L, 11L, 12L, 13L, 14L, 14L, 14L, 15L, 15L, 16L, 16L, 16L,
16L, 16L, 17L, 17L, 17L)), .Names = c("Site", "Nets", "Cumulative.spp"
), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L,
12L, 13L, 14L, 15L, 16L, 17L, 18L, 25L, 26L, 27L, 28L, 29L, 30L,
31L, 32L, 33L, 34L, 35L, 36L, 37L, 38L, 39L, 40L, 41L, 42L), class = "data.frame")
当我为一个人群建模时,一切看起来都很棒:
Model1<-nls(Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0), data = df1)
我想做的是看看我是否可以将多个群体添加到同一模型并添加一个站点变量,我试过这个:
Model2<-nls(Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0) + Site , data = df2)
还有这个:
Model2<-nls(Cumulative.spp ~ SSasympOff(Nets + Site , A, lrc, c0), data = df2)
但到目前为止运气不佳,我们将不胜感激。
我们假设您希望两个群体有不同的 Asym
参数,但有共同的 lrc
和 c0
参数。
首先在(1)中我们展示了如何修改问题中的解决方案以获得答案。 (1) 中的大部分代码只是为了获取起始值,但实际拟合只有一行代码——如果算上我们在单独的一行中定义公式这一事实,则为两行。
然后在 (2) 中,我们将展示如何通过使用算法 "plinear"
来简化 (1),从而无需获取线性参数的起始值。在 (2a) 中,我们展示了进一步的简化,它更容易扩展到更多站点,在 (2b) 中,我们在所有站点都存在的条件下进一步简化(问题中并非如此,但实际情况可能如此)数据)。
1) 默认算法 我们可以通过分别拟合每个群体 (fm1
, fm2
) 和一起拟合得到 nls
中的起始值(fm3
)。最后用不同的 Asym
参数拟合模型 (fm4
).
# get starting values
fo <- Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0)
fm1 <- nls(fo, df2, subset = Site == "ALT01")
fm2 <- nls(fo, df2, subset = Site == "ALT03")
fm3 <- nls(fo, df2)
st <- c(A1 = coef(fm1)[["A"]], A2 = coef(fm2)[["A"]], coef(fm3)[c("lrc", "c0")])
# fit
fo4 <- Cumulative.spp ~ SSasympOff(Nets, A1*(Site=="ALT01")+A2*(Site=="ALT03"), lrc, c0)
fm4 <- nls(fo4, data = df2, start = st)
plot(Cumulative.spp ~ Nets, df2, col = Site)
points(fitted(fm4) ~ Nets, df2, col = "red", pch = 20)
2) plinear 实际上 Asym
是特殊的,因为模型在其中是线性的,我们可以用它来简化上面的内容,因为我们不需要起始值对于线性参数,如果我们切换到 algorithm="plinear"
。这消除了 运行 fm1
和 fm2
的需要。我们只需要 fm3
来生成起始值。请注意,"plinear"
要求公式的 RHS 是一个矩阵,每一列乘以一个线性参数的系数。这里我们有两个线性参数(每个 Site
的 Asym
)所以它是一个双列矩阵。
# get starting values
fo <- Cumulative.spp ~ SSasympOff(Nets, A, lrc, c0)
fm3 <- nls(fo, df2)
st5 <- coef(fm3)[c("lrc", "c0")]
# fit
mm <- with(df2, cbind(Site=="ALT01", Site=="ALT03"))
fo5 <- Cumulative.spp ~ mm * SSasympOff(Nets,1,lrc,c0)
fm5 <- nls(fo5, data = df2, start = st5, algorithm = "plinear")
2a) mm
也可以这样写,它的优点是可以扩展到更多站点:
mm <- model.matrix(~ Site - 1, transform(df2, Site = droplevels(Site)))
2b) 如果 Site
因子的所有级别都在数据中表示,那么我们可以进一步简化为 droplevels(Site)
(这会删除未使用的级别)然后可以简单地 Site
允许我们写:
mm <- model.matrix(~ Site - 1, df2)
更新: 一些修复和改进。