Numbers-保存随机数生成器的状态

问题

你想要保存和回复随机数生成器的状态。

方案

.Random.seed保存到其他变量,之后将变量值赋给.Random.seed从而恢复原来的值。

# 这个例子中,先设定随机数种子
set.seed(423)
runif(3)
#> [1] 0.1089715 0.5973455 0.9726307

# 保存种子
oldseed <- .Random.seed

runif(3)
#> [1] 0.7973768 0.2278427 0.5189830

# 做其他随机数生成相关的事情,比如:
# runif(30)
# ...
# 回复种子
.Random.seed <- oldseed

# 保存种子之后,像之前那样得到相同的随机数
runif(3)
#> [1] 0.7973768 0.2278427 0.5189830

如果你之前还没有在R线程中用过随机数生成器,变量.Random.seed将会不存在。如果你对此不确定,应当在保存和恢复之前进行检查:

oldseed <- NULL
if (exists(".Random.seed"))
    oldseed <- .Random.seed

# 做一些随机数生成操作,比如:
# runif(30)
# ...

if (!is.null(oldseed))
    .Random.seed <- oldseed

在函数中保存和恢复随机数生成器的状态

如果你试图在函数中通过使用 .Random.seed <- x来恢复随机数生成器的状态,结果是行不通的,因为这个操作改变的是名为.Random.seed的本地变量,而不是全局环境中的这个变量。

这里有两个例子。这些函数想要做的是生成一些随机数,并使得随机数生成器保留未改变的状态。

# 这是个坏的版本
bad_rand_restore <- function() {
    if (exists(".Random.seed"))
        oldseed <- .Random.seed
    else
        oldseed <- NULL

    print(runif(3))

    if (!is.null(oldseed))
        .Random.seed <- oldseed
    else
        rm(".Random.seed")
}


# 这是个好的版本
rand_restore <- function() {
    if (exists(".Random.seed", .GlobalEnv))
        oldseed <- .GlobalEnv$.Random.seed
    else
        oldseed <- NULL

    print(runif(3))

    if (!is.null(oldseed)) 
        .GlobalEnv$.Random.seed <- oldseed
    else
        rm(".Random.seed", envir = .GlobalEnv)
}


# 坏的版本没有合适地重置随机数生成器状态,因此随机数一直在改变
set.seed(423)
bad_rand_restore()
#> [1] 0.1089715 0.5973455 0.9726307
bad_rand_restore()
#> [1] 0.7973768 0.2278427 0.5189830
bad_rand_restore()
#> [1] 0.6929255 0.8104453 0.1019465

# 好的版本每次都正确地重置了随机数生成器的状态,因此随机数可以保持一致
# stay the same.
set.seed(423)
rand_restore()
#> [1] 0.1089715 0.5973455 0.9726307
rand_restore()
#> [1] 0.1089715 0.5973455 0.9726307
rand_restore()
#> [1] 0.1089715 0.5973455 0.9726307

注意

使用者最好不要修改.Random.seed 变量。

人该是自己生活的主宰,而不是别人手里的行货