我正在使用R中的pscl
包并尝试使其生成可测试/可重现的结果。我已经看了一下底层的C代码并且出现了,好像在正确的位置调用了GetRNGstate()
和PutRNGstate()
但似乎无法重复输出MCMC模型。
我已经从 SoDA 包中的simulationResult
中打包了这些函数,因此我可以验证R端的每个模拟R的开始状态。
library(pscl)
library(SoDA)
run1 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0),
seed = 42)
run2 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0),
seed = 42)
我们可以验证起始状态至少在R方面是相同的:
all.equal(run1@firstState, run2@firstState)
但输出结果不同:
all.equal(run1@result$xbar, run2@result$xbar)
我可以增加迭代次数,但如果RNG状态正在传播,这应该不重要。我错过了一些非常简单的事吗?感谢。
编辑:我还应该注意all.equal(run1@lastState, run2@lastState)
(每次运行的结束状态)应该相同但最终会有所不同。我的猜测是,C调用的R RNG函数之外的一些偶然事件源正在影响调用这些RNG函数的数。好奇。
EDIT2
我还应该在OS X 10.8.4上使用pscl 1.04.4添加我的R 3.0.1。
答案 0 :(得分:7)
OP和@SchaunW怀疑,问题在于C代码。 “挖掘一点”揭示了一个相当微妙的问题(参见source代码,但不是最新版本):
ideal.c中的所有采样都出现在开始迭代的部分,即使用函数updatex
,updatey
和其他函数。然而,问题在于这些函数的一个参数 - 矩阵ok
(具有讽刺意味,对吧?)。它由updatex
和updateb
以及仅用于ok == 1
重要的位置in crosscheck
,{{1} })。
在此之前,crosscheckx
的某些值被ok
分配为1。
然而,在最开始时,check(y,ok,n,m)
的初始值由
ok
分配整数矩阵(参见util.c for ok = imatrix(n,m);
)。问题是,imatrix
包含各种数字,即不仅是零,有时是。似乎它们与R的RNG状态无关,这解释了@SchaunW注意到的行为:ok
如果all.equal(run1@result$xbar, run2@result$xbar)
则返回TRUE
,反之亦然。此外,不同数量的解释了不同的!any(ok == 1)
。
我不是C的专家,我不确定代码中是否存在逻辑错误,或者是否应更正lastState
函数,但可以直接修复imatrix
在初始化后立即使用零:
ok
最后,还有一个修复程序不包括修改C代码(虽然它可能不适合您的应用程序)。 ok = imatrix(n,m);
for(a=0; a<n; a++) {
for(aa=0; aa<m; aa++) {
ok[a][aa] = 0;
}
}
crossxyi
crossxyj
时,使用crosscheck
,crosscheckx
代替impute = TRUE
,ideal
(不好的)。
答案 1 :(得分:3)
修改强>
我无法重现我最初发布的结果。当我第一次得到这些结果时,我关闭了R,重新启动它,并再次运行整个过程以确保,我再次得到了相同的结果。下面显示的内容完全从我的R控制台复制。但是,我只是尝试了第三(以及第四和第五)时间的代码并且它无法正常工作。我正在离开原来的答案,以防万一我没有意识到它并且它可能对其他人有用,但下面的建议似乎不起作用(至少不一致)。
问题确实存在于C代码中。当我打开ideal
函数并逐行运行时,all.equal
对于此行代码中的每个输入都返回TRUE:
output <- .C("IDEAL", PACKAGE = .package.Name, as.integer(n),
as.integer(m), as.integer(d), as.double(yToC), as.integer(maxiter),
as.integer(thin), as.integer(impute), as.integer(mda),
as.double(xp), as.double(xpv), as.double(bp), as.double(bpv),
as.double(xstart), as.double(bstart), xoutput = as.double(rep(0,
n * d * numrec)), boutput = as.double(0), as.integer(burnin),
as.integer(usefile), as.integer(store.item), as.character(file),
as.integer(verbose))
但是,当我多次运行上述代码时,output$xoutput
每次都会返回略有不同的结果,即使我在每次运行之前立即调用set.seed(42)
。
sessionInfo()
R version 2.15.2 (2012-10-26)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] grid splines stats graphics grDevices utils datasets methods base
other attached packages:
[1] SoDA_1.0-5 pscl_1.04.4 vcd_1.2-13 colorspace_1.2-0 gam_1.06.2 coda_0.16-1 lattice_0.20-10 mvtnorm_0.9-9994
[9] MASS_7.3-22
loaded via a namespace (and not attached):
[1] tools_2.15.2
原始回答
ideal
函数有一个startvals
参数。该参数的默认值是“eigen”。要使您对set.seed
的调用生效,您需要将该参数更改为“随机”。这是你已经尝试过的:
run1 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0,
startvals = "eigen"),
seed = 42)
run2 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0,
startvals = "eigen"),
seed = 42)
all.equal(run1@firstState, run2@firstState)
[1] TRUE
all.equal(run1@result$xbar, run2@result$xbar)
[1] "Mean relative difference: 0.01832379"
这与startvals
设置为“随机”的情况相同:
run1 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0,
startvals = "random"),
seed = 42)
run2 <- simulationResult(
ideal(s109,
normalize=TRUE,
maxiter = 500,
thin = 10,
burnin = 0,
startvals = "random"),
seed = 42)
all.equal(run1@firstState, run2@firstState)
[1] TRUE
all.equal(run1@result$xbar, run2@result$xbar)
[1] TRUE
据我所知,在包文档中没有明确指出需要将startvals
设置为“随机”以获得可复制的结果。在我弄明白之前,我不得不玩了一会儿。
答案 2 :(得分:1)
这是一个MCMC模型,所以它必然使用随机数生成。要获得可重复的结果,您需要通过为随机数生成器设置“种子”来开始分析。这种方式每次构建模型时,它都使用相同的“随机”数字(只要您在每次构建模型时重置种子。使用set.seed()
函数,只需为它提供任意值,如{ {1}}。
我对这个软件包不熟悉,看起来您可能已经在使用1234
的函数调用中为随机数生成设置种子,但我建议使用{{1}明确设置它无论如何。然后你的代码变成:
seed=42