2.3 保持随机数生成器的状态

2.3.1 问题

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

2.3.2 方案

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

  1. # 这个例子中,先设定随机数种子
  2. set.seed(423)
  3. runif(3)
  4. #> [1] 0.1090 0.5973 0.9726
  5. # 保存种子
  6. oldseed <- .Random.seed
  7. runif(3)
  8. #> [1] 0.7974 0.2278 0.5190
  9. # 做其他随机数生成相关的事情,比如: runif(30) ...
  1. # 恢复种子
  2. .Random.seed <- oldseed
  3. # 保存种子之后,得到与之前相同的随机数
  4. runif(3)
  5. #> [1] 0.7974 0.2278 0.5190

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

  1. oldseed <- NULL
  2. if (exists(".Random.seed")) oldseed <- .Random.seed
  3. # 做一些随机数生成操作,比如: runif(30) ...
  4. if (!is.null(oldseed)) .Random.seed <- oldseed

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

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

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

  1. # 这是个坏的版本
  2. bad_rand_restore <- function() {
  3. if (exists(".Random.seed"))
  4. oldseed <- .Random.seed else oldseed <- NULL
  5. print(runif(3))
  6. if (!is.null(oldseed))
  7. .Random.seed <- oldseed else rm(".Random.seed")
  8. }
  9. # 这是个好的版本
  10. rand_restore <- function() {
  11. if (exists(".Random.seed", .GlobalEnv))
  12. oldseed <- .GlobalEnv$.Random.seed else oldseed <- NULL
  13. print(runif(3))
  14. if (!is.null(oldseed))
  15. .GlobalEnv$.Random.seed <- oldseed else rm(".Random.seed", envir = .GlobalEnv)
  16. }
  17. # 坏的版本没有正确地重置随机数生成器状态,因此随机数一直在改变
  18. set.seed(423)
  19. bad_rand_restore()
  20. #> [1] 0.1090 0.5973 0.9726
  21. bad_rand_restore()
  22. #> [1] 0.7974 0.2278 0.5190
  23. bad_rand_restore()
  24. #> [1] 0.6929 0.8104 0.1019
  25. # 好的版本每次都正确地重置了随机数生成器的状态,因此随机数可以保持一致
  26. set.seed(423)
  27. rand_restore()
  28. #> [1] 0.1090 0.5973 0.9726
  29. rand_restore()
  30. #> [1] 0.1090 0.5973 0.9726
  31. rand_restore()
  32. #> [1] 0.1090 0.5973 0.9726

2.3.2.2 注意

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