修复整个会话的set.seed

时间:2013-12-17 02:12:04

标签: 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

6 个答案:

答案 0 :(得分:22)

根据您的具体需求,有多种选择。我怀疑第一个选项,最简单的选择是不够的,但我的第二个和第三个选项可能更合适,第三个选项最自动化。

选项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)

(其中....表示函数的其他参数;这是伪代码)。

选项3

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

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

然后在使用中我们有:

> 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

答案 1 :(得分:13)

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

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

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

这个问题已经很久了,但搜索结果仍然很高,而且似乎值得在Spacedman的回答中进行扩展。

答案 2 :(得分:2)

没有必要。虽然结果与样本不同(您几乎肯定需要,否则随机性非常有问题),运行结果将是相同的。看,这是我机器的输出。

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

答案 3 :(得分:2)

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

> 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

可能有一种更优雅的方式,我相信有人会喜欢它。但是,如果他们不这样做,这将使你的生活更轻松。

答案 4 :(得分:0)

我建议您在调用R中的每个随机数生成器之前set.seed。我认为您需要的是可重复性用于蒙特卡罗模拟。如果在for循环中,您可以在调用set.seed(i)之前sample,这可以保证完全可重现。在您的外部函数中,您可以指定参数seed=1,以便在for循环中使用set.seed(i+seed)

答案 5 :(得分:0)

如果您想总是 从随机过程中返回相同的结果,只需使用以下方法始终保持种子设置:

addTaskCallback(function(...) {set.seed(123);TRUE})

现在每次输出都相同:

print(sample(1:10,3))
# [1] 3 8 4
print(sample(1:10,3))
# [1] 3 8 4