R 正在修复整个会话的set.seed

R 正在修复整个会话的set.seed,r,montecarlo,random-sample,agent-based-modeling,R,Montecarlo,Random Sample,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 没必要。虽然

我使用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

没必要。虽然每个样本的结果都不一样(这是您几乎肯定想要的,否则随机性是非常值得怀疑的),但每次运行的结果都是相同的。看,这是我机器的输出

> set.seed(123)
> sample(1:10,3)
[1] 3 8 4
> sample(1:10,3)
[1]  9 10  1

您可以执行包装器函数,如下所示:

> wrap.3.digit.sample <- function(x) {
+    set.seed(123)
+    return(sample(x, 3))
+ }
> wrap.3.digit.sample(c(1:10))
[1] 3 8 4
> wrap.3.digit.sample(c(1:10))
[1] 3 8 4
>wrap.3.digit.sample wrap.3.digit.sample(c(1:10))
[1] 3 8 4
>包装3.数字样品(c(1:10))
[1] 3 8 4

也许有一种更优雅的方式,我相信有人会赞同。但是,如果他们不这样做,这应该会让你的生活更轻松。

我建议你在调用R中的每个随机数生成器之前设置.seed。我认为你需要的是蒙特卡罗模拟的再现性。如果在
for
循环中,您可以在调用
sample
之前
设置.seed(i)
,这保证了完全可复制。在外部函数中,您可以指定一个参数
seed=1
,以便在
for
循环中,使用
set.seed(i+seed)
,根据您的具体需要,有几个选项。我怀疑第一个选项,最简单的是不够的,但我的第二个和第三个选项可能更合适,第三个选项是最自动化的

选择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
选择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)
在使用中,我们有:

> 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

我认为这个问题令人困惑。在本例中,已为整个会话设置种子。但是,这并不意味着每次在运行期间使用
print(sample))
命令时,它都会生成相同的一组数字;这不会像一个随机过程,因为它将完全确定每次都会出现相同的三个数字。相反,实际发生的情况是,一旦设置了种子,每次运行脚本时,都会使用相同的种子生成伪随机数字选择,也就是说,这些数字看起来似乎是随机的,但实际上是通过使用已设置种子的可复制过程生成的

如果从一开始就重新运行整个脚本,则会复制看似随机但并非随机的数字。因此,在本例中,第二次将种子设置为123时,输出再次为9、10和1,这正是您希望看到的结果,因为该过程将从头开始。如果您要通过写入
print(示例(1:10,3))
继续复制第一次运行,那么第二组输出将再次为3、8和4

因此,对这个问题的简短回答是:如果你想设定一个种子来创造一个可复制的过程,那么做你已经做的事情,设定一次种子;但是,您不应该在每次随机抽取之前设置种子,因为这将从一开始就再次启动伪随机过程

这个问题很老了,但在搜索结果中仍然很重要,似乎值得在Spacedman的答案上进行扩展。

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

addTaskCallback(function(...) {set.seed(123);TRUE})
现在,每次输出都是相同的:

打印(样本(1:10,3))
# [1] 3 8 4
打印(样本(1:10,3))
# [1] 3 8 4

为什么要将它们全部修复?仅仅在开始时设置一次种子,然后运行3个或多个操作还不够吗?如果您在开始时设置一次种子,并且从不触摸它,您将从计算机程序中获得可复制的结果。例如,如果希望使用随机数的代理在每次执行操作时表现相同,则可能需要在程序中设置种子。在这种情况下,让代理设定它的种子。我不认为你所说的从OP得到了重点。我认为重点是“可复制”的结果。你可以得到不同的样品,但在你的电脑里你无法控制它approach@alittleboy好吧,现在还不清楚OP需要什么。例如,如果我有一个脚本调用函数
foo()
4次,并且每一次都使用10个随机数,那么我所需要做的就是在脚本开始时设置一次种子。如果运行脚本,结果是可复制的。如果您需要单独运行并独立运行,那么您需要另一种方法。你的答案是一个,非常具体,并且假设OP没有说很多。例如,我做了很多蒙特卡罗的事情,我不会按照你的方式做。所以上下文就是这里的一切。@GavinSimpson问题是长度是动态的,因为代理模型是动态的。然后,因为结构是不固定的,我可以得到相同的种子不同的结果。我认为这是你提出问题的有用信息。在这种情况下,您可能希望遵循我的答案中的选项2或3。但我不确定你真的想这么做;函数的每次调用都将使用完全相同的初始随机数集,直到动态位生效,这有关系吗?@GavinSimpson你是对的,这应该是问题的一部分。从这里的讨论中,我更加怀疑正确的实施。让我们看看我的顾问怎么说。。谢谢你
addTaskCallback(function(...) {set.seed(123);TRUE})