修复整个会话的set.seed

Ela*_*663 24 r random-sample montecarlo agent-based-modeling

我使用R构建一个基于代理的模型,使用蒙特卡罗过程.这意味着我有许多使用某种随机引擎的函数.为了获得可重复的结果,我必须修复种子.但是,据我所知,我必须在每个随机抽签或样本之前设置种子.这是一个真正的痛苦.有没有办法修理种子?

set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4
print(sample(1:10,3))
# [1]  9 10  1
set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4
Run Code Online (Sandbox Code Playgroud)

Rei*_*son 23

有几种选择,具体取决于您的确切需求.我怀疑第一个选项,最简单的选择是不够的,但我的第二个和第三个选项可能更合适,第三个选项最自动化.

选项1

如果您事先知道使用/创建随机数的函数将始终绘制相同的数字,并且您没有对函数调用重新排序或在现有函数之间插入新调用,那么您只需将种子设置一次.实际上,您可能不希望继续重置种子,因为您将继续为每个函数调用获取相同的随机数集.

例如:

> set.seed(1)
> sample(10)
 [1]  3  4  5  7  2  8  9  6 10  1
> sample(10)
 [1]  3  2  6 10  5  7  8  4  1  9
> 
> ## second time round
> set.seed(1)
> sample(10)
 [1]  3  4  5  7  2  8  9  6 10  1
> sample(10)
 [1]  3  2  6 10  5  7  8  4  1  9
Run Code Online (Sandbox Code Playgroud)

选项2

如果您确实希望确保函数使用相同的种子而您只想设置一次,请将种子作为参数传递:

foo <- function(...., seed) {
  ## set the seed
  if (!missing(seed)) 
    set.seed(seed) 
  ## do other stuff
  ....
}

my.seed <- 42
bar <- foo(...., seed = my.seed)
fbar <- foo(...., seed = my.seed)
Run Code Online (Sandbox Code Playgroud)

(这....意味着你的函数的其他args;这是伪代码).

选项3

如果你想更自动化这个,那么你可能会滥用这个options机制,如果你只是在脚本中执行此操作就没问题(对于一个包你应该使用自己的选项对象).然后您的函数可以查找此选项.例如

foo <- function() {
  if (!is.null(seed <- getOption("myseed")))
    set.seed(seed)
  sample(10)
}
Run Code Online (Sandbox Code Playgroud)

然后在使用中我们有:

> getOption("myseed")
NULL
> foo()
 [1]  1  2  9  4  8  7 10  6  3  5
> foo()
 [1]  6  2  3  5  7  8  1  4 10  9
> options(myseed = 42)
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
> foo()
 [1] 10  9  3  6  4  8  5  1  2  7
Run Code Online (Sandbox Code Playgroud)


小智 13

我认为这个问题存在混淆.在这个例子中,种子已经被定为整个会话.但是,这并不意味着每次print(sample))在运行期间使用该命令时它将生成相同的数字集; 这不会像一个随机过程,因为完全可以确定每次都会出现相同的三个数字.相反,实际发生的是,一旦你设置了种子,每次运行一个脚本时,相同的种子就会产生一个伪随机的数字选择,也就是说,数字看起来好像是随机的但实际上是使用您设定的种子通过可重复的过程生成.

如果从头开始重新运行整个脚本,则会重现那些看起来随机但不是的数字.因此,在示例中,第二次将种子设置为123时,输出又是9,10和1,这正是您期望看到的,因为该过程从头开始.如果你通过写作继续重现你的第一次运行print(sample(1:10,3)),那么第二组输出将再次是3,8和4.

所以这个问题的简短答案是:如果你想设置一个种子来创建一个可重复的过程,那就做你做过的事情并设置一次种子; 但是,你应该不会设置种子每次随机抽签之前,因为这将再次从头开始的伪随机过程.

这个问题很老,但搜索结果仍然很高,而且似乎值得在Spacedman的回答中扩展.


use*_*745 8

如果您想始终从随机过程返回相同的结果,只需始终保持种子集:

addTaskCallback(function(...) {set.seed(123);TRUE})
Run Code Online (Sandbox Code Playgroud)

现在输出每次都一样:

addTaskCallback(function(...) {set.seed(123);TRUE})
Run Code Online (Sandbox Code Playgroud)