我正在分析一个数据集,其中包含树木测量值,例如直径(厘米)以及它是死是活(0/1)。测量收集是不定期的,即从 1960 年开始,至今仍在测量中。迄今为止,已在广阔的地理区域内总共建立了 10,000 个样地,所有高度超过 1.3 m 的树木都被永久标记和监控。这也意味着,如果该地块中长出了新树并且它们超过了 1.3m,它们也会包含在集合中。每个地块平均包含约 100 棵树。大多数地块每 5-7 年左右测量一次,有些地块只测量两次,有些地块超过 10 次,这意味着我对独特的树木进行了重复测量。一旦一棵树死亡,它的最终直径就会被记录下来,然后排除在进一步的测量之外。
这是数据子集的一些结构:
> glimpse(d)
Rows: 15,472
Columns: 12
$ plot_number <dbl> 272.1, 272.1, 272.1, 272.1, 272.1, 272.1, 272.1, 27…
$ establishment_year <dbl> 1965, 1965, 1965, 1965, 1965, 1965, 1965, 1965, 196…
$ measurement_year <dbl> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 197…
$ measurement_interval <dbl> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,…
$ tree_number <dbl> 1, 5, 6, 7, 12, 15, 18, 19, 20, 22, 24, 26, 27, 29,…
$ species <chr> "Pl", "Pl", "Pl", "Pl", "Pl", "Pl", "Pl", "Pl", "Pl…
$ dbh <dbl> 27.9, 30.2, 13.0, 14.2, 10.9, 19.8, 9.1, 36.8, 24.4…
$ survival <dbl> 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
$ tree_id <chr> "272.1-1", "272.1-5", "272.1-6", "272.1-7", "272.1-…
> d %>%
+ group_by(plot_number, measurement_year) %>%
+ summarise(number_of_trees = n())
`summarise()` has grouped output by 'plot_number'. You can override using
the `.groups` argument.
# A tibble: 210 × 3
# Groups: plot_number [72]
plot_number measurement_year number_of_trees
<dbl> <dbl> <int>
1 6.1 1965 33
2 6.1 1968 37
3 6.1 1973 34
4 6.1 1982 23
5 6.1 1992 11
6 6.2 1965 35
7 6.2 1968 34
8 6.2 1973 34
9 6.2 1982 28
10 6.2 1992 20
# ℹ 200 more rows
# ℹ Use `print(n = ...)` to see more rows
> d %>%
+ group_by(plot_number, tree_number) %>%
+ summarise(tree_measurements = n()) %>%
+ arrange(plot_number, tree_number)
`summarise()` has grouped output by 'plot_number'. You can override using
the `.groups` argument.
# A tibble: 6,725 × 3
# Groups: plot_number [72]
plot_number tree_number tree_measurements
<dbl> <dbl> <int>
1 6.1 531 4
2 6.1 532 3
3 6.1 533 5
4 6.1 534 3
5 6.1 536 3
6 6.1 537 4
7 6.1 540 2
8 6.1 542 4
9 6.1 543 2
10 6.1 546 3
# ℹ 6,715 more rows
# ℹ Use `print(n = ...)` to see more rows
我想使用这些数据来生成按物种的生存模型,即生存作为直径的函数(带有置信带的拟合值)。
在R中,我是这样做的:
require(glmmTMB)
require(ggeffects)
m <- glmmTMB(survival ~ dbh + (1|tree_id) ,
family = binomial(link = "logit"),
data = d)
m_pred <- ggpredict(m, terms = "dbh [all]")
plot(m_pred)
但是,需要根据同一棵树的后续测量之间的时间来调整预测值。在文献中,对于 5-7 年的间隔长度,建议使用以下广义逻辑模型(A Generalized Mixed Logistic Model for Predicting individual Tree Survival Probability with UnequalMeasurement Intervals):
$$P = \left( rac{e^ ta}{1 + e^ ta} 右)^{\Delta t}$$
这是我必须转向 SAS proc nlmixed 的地方,因为我无法找到在 R 中编码的方法(尽管有一个 @BenBolker hack here 似乎适用于我的数据)。不管怎样,我也想在 SAS 中运行它,然后与 Ben Bolker 的代码进行比较。这是我使用的 SAS 代码:
proc nlmixed data=d;
parms b0=1 b1=0.01 ss=1;
eta = (b0+u1)+b1*dbh ;
prob = (exp(eta)/(1+exp(eta)))**measurement_interval; /*ADJUSTED LOGISTIC FUNCTION*/
model survival ~ binary(prob);
random u1 ~ normal(0,ss*ss) subject= tree_id;
predict prob out=predv;
predict u1 out=ran;
run;
我现在无法弄清楚的是如何获得与上面相同的图(带有置信带的拟合值)...我确实使用了SAS中的
predict
选项,但预测值似乎是个体的预测值观测值而不是拟合值。虽然,我可以使用估计的模型参数创建拟合线(如上所述),但我不知道如何为这些拟合值添加置信带。
在此网站上(https://stats.oarc.ucla.edu/sas/faq/how-can-i-run-simple-linear-and-nonlinear-models-using-nlmixed/)是一个链接PROC NLMIXED 的 SAS 玩具数据集。使用这个数据集,我运行了以下代码,生成了这个图表(我不想要):
proc nlmixed data="C:\hsbdemo.sas7bdat";
parms b0=5 b1=0 ss=1;
xb=(b0+u1)+b1*read;
prob = exp(xb)/(1+exp(xb));
model honors ~ binary(prob);
random u1 ~ normal(0,ss*ss) subject = ses;
predict prob out=pred;
run;
proc sgplot data=pred;
series x=read y=pred / lineattrs=(color=blue);
band x=read lower=lower upper=upper / transparency=0.5;
xaxis label="Read";
yaxis label="Predicted Probability";
run;
所以我的问题是如何使用 SAS 和 PROC NLMIXED 复制 R 中生成的图(上面的第一个图)?
编辑
根据@Tom的建议,这是一种计算所需置信区间的方法。以下示例是在 R 中使用的,但我希望它可以在 SAS 中工作,以在 PROC NLMIXED 中运行模型。我添加了注释,希望能够足够清楚地解释这些步骤,以便那些不了解 R 但了解 SAS 的人可以复制它。然而,理想情况下,我想要一个 SAS 程序,通过编程来执行此操作,而不是手动执行此操作。
require(haven)
require(ggeffects)
require(glmmTMB)
# read data (https://stats.oarc.ucla.edu/sas/faq/how-can-i-run-simple-linear-and-nonlinear-models-using-nlmixed/)
d <- read_sas("hsbdemo.sas7bdat")
# run logistic regression
m <- glmmTMB(HONORS ~ READ + (1|SES), data = d, family = binomial(link = "logit"))
# extract fixed effects parameter estimates
coef <- fixef(m)$cond
# create data frame with sequence of predictions
new_preds <- data.frame(INTERCEPT = 1, READ = seq(min(d$READ),max(d$READ), by = 0.1))
# create design matrix
X <- as.matrix(new_preds)
# matrix multiply design matrix with parameter vector to get predictions
eta <- X %*% coef
# extract variance-covariance matrix
vcov_model <- vcov(m)$cond
# matrix multiply design matrix with variance covariance matrix with the transpose of the design matrix
vcov_preds <- diag(X %*% vcov_model %*% t(X))
# calculate standard deviations (errors)
se_logit <- sqrt(vcov_preds)
# transform prediction from logit to probability scale
prob <- plogis(eta)
# calculate confidence intervals and transform from logit to probability scale
lower <- plogis(eta - 1.96 * se_logit)
upper <- plogis(eta + 1.96 * se_logit)
# plot results
plot(new_preds$READ, prob)
lines(new_preds$READ, lower, col = "red")
lines(new_preds$READ, upper, col = "red")
这就是它应该的样子(不像上面的那样)。
这个图可以重现为适合 PROC NLMIXED 的模型吗?
我在寻找一种使用 nlmixed 在回归线上添加置信区间带的方法时看到了你的帖子。如果通过 read(x 变量) 对预测输出进行排序,由于随机效应,您将得到合理但锯齿状的线条和带。
proc sort data=pred_n;
by read;
run;
[绘图前对 x 变量进行排序][1]
https://agstats.io/tutorials/sas-nonlinear的帖子(8混合模型估计下的示例)展示了一个调整随机效应预测函数的示例,无需预测语句中的随机参数即可得到像这样的:
predict exp(b0+b1*(read))/(1+exp(b0+b1*(read))) out=pred;
[预测函数中没有随机参数][2]