我有以下潜变量模型:人 j 有两个潜变量,Xj1 和 Xj2。我们唯一能观察到的是它们的最大值,Yj = max(Xj1, Xj2)。潜在变量是二元正态的;它们每个都有均值 mu、方差 sigma2,并且它们的相关性是 rho。我想仅使用 Yj 来估计三个参数(mu、sigma2、rho),数据来自 n 个患者,j = 1,...,n。
我试图在 JAGS 中拟合这个模型(所以我将先验放在参数上),但我无法编译代码。这是我用来调用 JAGS 的 R 代码。首先,给定参数的一些真实值,我生成数据(潜在变量和观察变量):
# true parameter values
mu <- 3
sigma2 <- 2
rho <- 0.7
# generate data
n <- 100
Sigma <- sigma2 * matrix(c(1, rho, rho, 1), ncol=2)
X <- MASS::mvrnorm(n, c(mu,mu), Sigma) # n-by-2 matrix
Y <- apply(X, 1, max)
然后我定义了 JAGS 模型,并编写了一个小函数来运行 JAGS 采样器并返回样本:
# JAGS model code
model.text <- '
model {
for (i in 1:n) {
Y[i] <- max(X[i,1], X[i,2]) # Ack!
X[i,1:2] ~ dmnorm(X_mean, X_prec)
}
# mean vector and precision matrix for X[i,1:2]
X_mean <- c(mu, mu)
X_prec[1,1] <- 1 / (sigma2*(1-rho^2))
X_prec[2,1] <- -rho / (sigma2*(1-rho^2))
X_prec[1,2] <- X_prec[2,1]
X_prec[2,2] <- X_prec[1,1]
mu ~ dnorm(0, 1)
sigma2 <- 1 / tau
tau ~ dgamma(2, 1)
rho ~ dbeta(2, 2)
}
'
# run JAGS code. If latent=FALSE, remove the line defining Y[i] from the JAGS model
fit.jags <- function(latent=TRUE, data, n.adapt=1000, n.burnin, n.samp) {
require(rjags)
if (!latent)
model.text <- sub('\n *Y.*?\n', '\n', model.text)
textCon <- textConnection(model.text)
fit <- jags.model(textCon, data, n.adapt=n.adapt)
close(textCon)
update(fit, n.iter=n.burnin)
coda.samples(fit, variable.names=c("mu","sigma2","rho"), n.iter=n.samp)[[1]]
}
最后,我调用 JAGS,只提供观察到的数据:
samp1 <- fit.jags(latent=TRUE, data=list(n=n, Y=Y), n.burnin=1000, n.samp=2000)
遗憾的是,这会导致错误消息:“Y[1] 是一个逻辑节点,无法观察”。 JAGS 不喜欢我使用“
此外,为了证明其他一切(除了“Ack!”行)都很好,我再次运行模型,但这次我向它提供 X 数据,假装它确实被观察到了。这运行完美,我得到了很好的参数估计:
samp2 <- fit.jags(latent=FALSE, data=list(n=n, X=X), n.burnin=1000, n.samp=2000)
colMeans(samp2)
如果您能找到一种在 STAN 而不是 JAGS 中对该模型进行编程的方法,那对我来说没问题。
最佳答案
从理论上讲,您可以使用 dsum 分布在 JAGS 中实现这样的模型(在这种情况下,在建模两个变量的最大值而不是总和时使用了一些技巧)。但是以下代码确实可以编译并运行(尽管它在任何真正意义上都不起作用 - 见下文):
set.seed(2017-02-08)
# true parameter values
mu <- 3
sigma2 <- 2
rho <- 0.7
# generate data
n <- 100
Sigma <- sigma2 * matrix(c(1, rho, rho, 1), ncol=2)
X <- MASS::mvrnorm(n, c(mu,mu), Sigma) # n-by-2 matrix
Y <- apply(X, 1, max)
model.text <- '
model {
for (i in 1:n) {
Y[i] ~ dsum(max_X[i])
max_X[i] <- max(X[i,1], X[i,2])
X[i,1:2] ~ dmnorm(X_mean, X_prec)
ranks[i,1:2] <- rank(X[i,1:2])
chosen[i] <- ranks[i,2]
}
# mean vector and precision matrix for X[i,1:2]
X_mean <- c(mu, mu)
X_prec[1,1] <- 1 / (sigma2*(1-rho^2))
X_prec[2,1] <- -rho / (sigma2*(1-rho^2))
X_prec[1,2] <- X_prec[2,1]
X_prec[2,2] <- X_prec[1,1]
mu ~ dnorm(0, 1)
sigma2 <- 1 / tau
tau ~ dgamma(2, 1)
rho ~ dbeta(2, 2)
#data# n, Y
#monitor# mu, sigma2, rho, tau, chosen[1:10]
#inits# X
}
'
library('runjags')
results <- run.jags(model.text)
results
plot(results)
有两点需要注意:
据我所知,“我如何编码这个”问题的其他潜在解决方案将陷入本质上相同的非混合陷阱,我认为这是这里的一个基本问题(尽管我可能是错的,并且非常欢迎工作BUGS/JAGS/Stan 代码,否则说明)。
混合失败的解决方案更难,尽管类似于用于模型选择的 Carlin & Chibb 方法可能有效(强制 min(pseudo_X) 参数等于 Y 以鼓励切换)。这可能很难开始工作,但是如果您可以从具有合理 BUGS/JAGS 经验的人那里获得帮助,您可以尝试一下 - 请参阅:
Carlin, B.P., Chib, S., 1995. 通过马尔可夫链蒙特卡罗方法选择贝叶斯模型。 J. R. 统计社会。爵士。 B 57, 473–484。
或者,您可以尝试稍微不同地考虑这个问题,并将 X 直接建模为一个矩阵,其中第一列全部缺失,第二列全部等于 Y。然后您可以使用 dinterval() 对它们的缺失值设置约束必须低于相应的最大值。我不确定这在估计 mu/sigma2/rho 方面效果如何,但可能值得一试。
顺便说一句,我意识到这不一定能回答您的问题,但我认为这是“是否可编码”和“是否可行”之间区别的一个有用示例。
马特
附:一个更聪明的解决方案是直接考虑两个正态变量的最大值的分布 - 我不确定这样的分布是否存在,但它确实存在,你可以获得它的 PDF 然后可以直接使用分布编码零/一技巧而无需考虑最小值的值。
关于r - 当观察到的节点是最大潜在节点时使用 JAGS 或 STAN,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40557643/