R包pscl中的ideal()不会产生可重复的结果

时间:2013-06-07 16:43:50

标签: r mcmc pscl

我正在使用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。

3 个答案:

答案 0 :(得分:7)

OP和@SchaunW怀疑,问题在于C代码。 “挖掘一点”揭示了一个相当微妙的问题(参见source代码,但不是最新版本):

ideal.c中的所有采样都出现在开始迭代的部分,即使用函数updatexupdatey和其他函数。然而,问题在于这些函数的一个参数 - 矩阵ok(具有讽刺意味,对吧?)。它由updatexupdateb以及用于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时,使用crosscheckcrosscheckx代替impute = TRUEideal(不好的)。

答案 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