尽管指定了 for 循环,但它不会更改每次迭代时生成的随机值

For loop is not changing the random values generated at each iteration despite specifying it to

我目前正在为 运行 二维空间自适应样条拟合技术的模拟编写代码,在这段代码中我有一个 for 循环,它应该改变我从中构建模型的 x、y 和 z 值每次迭代。

N.B。要 运行 此代码,您需要 github 的 MRSea 软件包。这个可以 使用以下方式下载: devtools::install_git("https://github.com/lindesaysh/MRSea.git")

经过一些非常有用的评论(感谢大家),我将代码缩减为:


simulate <- function(niter=5, npoints=10, nknots=9, fitmeasure="AIC", startknots=5, minknots=2,maxknots=9, knotgap=0 ) {
  require(MRSea)
  x <- matrix(nrow=niter, ncol=npoints)
  y <- matrix(nrow=niter, ncol=npoints)
  rnd <- matrix(nrow=niter, ncol=npoints)
  mygrid <- expand.grid(seq(0,1, length=npoints), seq(0,1, length=npoints)) 
  for (i in 1:niter) {
    x[i,] <- runif(npoints)  
    y[i,] <- runif(npoints) 
    mu <- x[i,]*sin(4*pi*y[i,]) 
    sigma <- diff(0.25 * range(mu)) 
    rnd[i,] <- rnorm(npoints)
    z <- mu + sigma*rnd[i,]
    dat <- data.frame(x.pos=x[i,], y.pos=y[i,], response=z)
    init <- glm(response ~ 1, data=dat)
    knotgrid <- getKnotgrid(coordData = cbind(x[i,],y[i,]), numKnots = nknots, plot=F) 
    distMats <- makeDists(cbind(x[i,],y[i,]), na.omit(knotgrid))
    salsa2dlist <-  list(fitnessMeasure = fitmeasure, knotgrid = knotgrid,
                         startKnots=startknots, minKnots=minknots, maxKnots=maxknots, gap=knotgap)
    predgrid <- makeDists(mygrid, na.omit(knotgrid))$dataDist
    sim <- runSALSA2D(model=init, salsa2dlist, d2k=distMats$dataDist,
                      k2k=distMats$knotDist, splineParams=NULL, tol=0, chooserad=F,
                      panels=NULL, suppress.printout=TRUE)

  }
  return(x) # Can return x,y or rnd to see the issue
}
simulate()

我已经确定删除以下代码行允许 运行if() 行正确 运行 并产生不同的值:

sim <- runSALSA2D(model=init, salsa2dlist, d2k=distMats$dataDist,
                      k2k=distMats$knotDist, splineParams=NULL, tol=0, chooserad=F,
                      panels=NULL, suppress.printout=TRUE)

有谁知道为什么这一行可能会导致我的代码出现问题以及可能的解决方法?

谢谢。

某事 正在设置随机种子。也许 knot.seed 参数?尽管这似乎更有可能是一些结。无论如何,一个快速的解决方法是在随机数生成之前输入 set.seed(as.integer(Sys.time()) %% 10000)

深入挖掘以找出设置种子的函数可能是明智的,因为它可能会或可能不会影响您的结果。

"Use the source, Luke..." runSALSA2D 调用 getCVids,这会重置种子。它真的应该只在函数内部这样做,而不影响函数外部的种子;您可以就此提出 bug/feature 请求。您可以向函数发送不同的种子,但由于它使用 set.seed,因此没有一种简单的方法可以保持随机数生成器的良好属性。当然,每次都使用相同的种子可能会导致其他问题,因此您可能想尝试一下;从帮助文件中,传递 NULL 可能是最好的(除了根本不设置种子!),但这就是 runSALSA2D 在硬设置之前检查的内容。 :(

https://github.com/lindesaysh/MRSea/blob/master/R/runSALSA2D.R https://github.com/lindesaysh/MRSea/blob/master/R/getCVfoldID.R

不过,与此同时,您需要做的就是在每次循环中生成数字后保存种子,然后自行重置。

runif(1)
saved.seed <- .Random.seed
for (i in 1:niter) {
    .Random.seed <- saved.seed
    x[i,] <- runif(npoints)  
    y[i,] <- runif(npoints) 
    mu <- x[i,]*sin(4*pi*y[i,]) 
    sigma <- diff(0.25 * range(mu)) 
    rnd[i,] <- rnorm(npoints)
    saved.seed <- .Random.seed

第一个runif(1)是确保.Random.seed存在;参见 setting seed locally (not globally) in R

或者(无论如何,对于所写的示例),您不会产生很多积分;您也可以一次生成它们并保存它们以在循环中使用。

编辑:是的,这样做!

无论如何,您已经为顶部的所有随机点分配了 space!所以他们根本没有理由参与其中。

simulate3 <- function(...) {
  x <- matrix(runif(npoints*niter), nrow=niter, ncol=npoints)
  y <- matrix(runif(npoints*niter), nrow=niter, ncol=npoints)
  rnd <- matrix(rnorm(npoints*niter), nrow=niter, ncol=npoints)
  mygrid <- expand.grid(seq(0,1, length=npoints), seq(0,1, length=npoints)) 
  for(i in 1:niter) {
    mu <- x[i,]*sin(4*pi*y[i,]) 
    sigma <- diff(0.25 * range(mu)) 
    z <- mu + sigma*rnd[i,]