在 R 包 mgcv 中,对两个连续变量进行平滑随机效应是否有效?

机器算法验证 r 毫克CV
2022-04-09 14:35:34

在我的模型中,我有两个变量,距离和时间,它们会影响不同主题的表现(成功或失败)。距离和时间之间的关系是非线性的,不能分成单个加法项,并且(可能)因主题而异。模型中的其他术语还涉及其他变量,但我目前的重点是这两个变量。

我没有我可以期待的参数形式,但我确实对数百个受试者进行了数千次观察,因此可以非参数地估计距离和时间之间的整体交互。我一直在使用 mgcv::bam(mgcv::gam 的大数据版本)来估计一个(简化的)模型,如下所示:

mgcv::bam(success ~ s(distance, time), data=mydata)

然而,我想探索的是,这种距离+时间的关系如何在不同的主题中变化,使用随机效应框架。就像是:

mgcv::bam(success ~ s(distance, time, subject, bs="re"), data=mydata)

以这种方式运行 R 代码不会产生错误,但我不确定它是否按照我的想法运行。我还没有找到任何关于在 mgcv 随机效应中使用多个数值变量的参考,并且想知道是否有这样做的原因。

作为旁注,一种方法可能是将距离和时间组合成一个变量,如“速度”(距离/时间),然后使用:

mgcv::bam(success ~ s(speed, subject, bs="re"), data=mydata)

...但这可能会以距离和时间交互的复杂方式丢失一些细节,从而导致我的问题。

查阅 R 中 mgcv::gam 函数的文档,您可以将因子变量上的平滑指定为另一个数值变量的随机斜率。

如果 g 是一个因子并且 x 是数字,那么 s(x,g,bs="re") 会产生一个 iid 正态随机斜率,该斜率将每个 g 水平的响应与 x 相关联。

我不清楚您是否可以指定多个数字变量以及随机效果平滑。即 s(x, y, g, bs="re")。或者即使这是一个明智的想法。

简化示例:

## adapted from example in mgcv docs
dat <- gamSim(1,n=400,scale=2) ## simulate 4 term additive truth

fac <- sample(1:20,400,replace=TRUE)
b <- rnorm(20)*.5
dat$y <- dat$y + b[fac]
dat$fac <- as.factor(fac)

rm1 <- gam(y ~ s(x0, fac,bs="re") + s(x1, x2, fac, bs="re") +    s(x3),data=dat,method="ML")

根据文档,x0 和 fac 上的平滑是可以的,但我不知道 x1、x2 和 fac 上的平滑是否有效且可解释。

2个回答

考虑示例的随机效应部分

toy <- gam(y ~ s(x0, fac, bs = "re") + s(x1, x2, fac, bs="re"),
           data = dat, method = "REML")

这只是以下线性回归模型的惩罚版本:

toy.lm <- lm(y ~ x0:fac + x1:x2:fac, data = dat)

其中,岭惩罚适用于x0:facx1:x2:fac


mgcv::gam在or中构建简单随机效应mgcv::bam是相当常规的:

  • 生成设计矩阵

    X1 <- model.matrix(~x0:fac - 1, data = dat)
    X2 <- model.matrix(~x1:x2:fac - 1, data = dat)
    
  • 生成岭惩罚矩阵

    S2 <- S1 <- diag(nlevels(dat$fac))
    

嗯...我在 SO 上以访客身份发帖,因为我仍然处于暂停状态,但后来问题转移到了这里!

所以,如果我理解正确的话,平滑 s(x1, x2) 和随机效应 s(x1, x2, fac, bs = "re") 之间并没有任何相似之处,对吗?

正确的。s()函数名“s”在用于构造随机效果时并不表示“平滑函数” 。从广义上讲,s()只是一个模型项构造函数例程,它构造了一个设计矩阵和一个惩罚矩阵。

我的设想是像前者一样在二维上进行平滑处理,但与因子水平的平均值有一些偏差。您可以使用 s(x1, x2, by=fac) 对每个因子级别进行单独的平滑处理,但这会完全分离每个因子级别的数据,而不是进行一些部分合并。

s(x1, x2, by = fac)给你一些非常接近你想要的东西,除了如你所说,来自不同因子水平的数据是独立处理的。从技术上讲,“关闭”意味着s(x1, x2, by = fac)给你正确的设计矩阵,但不是正确的惩罚矩阵。在这方面,您的目标可能是te(x1, x2, fac, d = c(2, 1), bs = c("tp", "re")). 我以前从未见过这样的模型术语,但它的构造绝对是可能的mgcv

library(mgcv)

x1 <- runif(1000)
x2 <- runif(1000)
f <- gl(5, 200)

## "smooth.spec" object
smooth_spec <- te(x1, x2, f, d = c(2, 1), bs = c("tp", "re"))

## "smooth" object
sm <- smooth.construct(smooth_spec,
                       data = list(x1 = x1, x2 = x2, f = f),
                       knots = NULL)

您可以检查此平滑项是否如预期具有 2 个平滑参数,一个用于s(x1, x2, bs = 'tp')边距,另一个用于s(f, bs = 're')边距。

结果的规格k很微妙。您需要显式传递nlevels(f)给随机效果边距。例如,如果你想要一个 rank-10 薄板回归样条,

## my example factor `f` has 5 levels
smooth_spec <- te(x1, x2, f, d = c(2, 1), bs = c("tp", "re"), k = c(10, 5))
sapply(smooth_spec$margin, "[[", "bs.dim")
# [1] 10  5

起初我在想也许我们可以简单地传递NA给随机效应边距,但事实证明不是!

smooth_spec <- te(x1, x2, f, d = c(2, 1), bs = c("tp", "re"), k = c(10, NA))
sapply(smooth_spec$margin, "[[", "bs.dim")
# [1] 25  5  ## ?? why is it 25? something has gone wrong!

这可能意味着有一个小错误......将在可用时进行检查。