我能否以某种方式获得.seed()?

65

关于set.seed()语句,如果我没有显式设置它,那么在运行一些代码后我能得到种子吗?

我一直在重新运行一些代码(交互式/控制台中) ,其中包含一个随机化输入数据的函数(该函数是kohonen包的一部分)。 在尝试多次后以查看输出结果的多样性(这是一个"不稳定"问题),我发现了一个相当有趣的结果。 当然,我没有使用set.seed(),但我想知道是否可以在运行代码后获取种子以重新生成结果?

?set.seed中,我看到:

.Random.seed保存为均匀随机数生成器设置的种子

但是我不知道这如何帮助我。


1
William Dunlap在这里的回答中提供了一些相关信息。 - gung - Reinstate Monica
5个回答

55

如果你没有保留种子,那么在观察到一个随机数后,没有通用的方法可以“回滚”随机数生成器到先前的状态。接下来,你可能想要做的是将 .Random.seed 的值与你的计算结果一起保存。可以像这样:

x <- .Random.seed
result <- <your code goes here>
attr(result, "seed") <- x

你可以按以下方式重置PRNG;result2 应该与 result 相同。

.Random.seed <- attr(result, "seed")
result2 <- <your code goes here>

谢谢Hong。我刚刚对与在控制台工作有关的问题进行了澄清,但我认为你已经提供了解决方案。我在运行代码后仍然可以保存.Random.seed,对吗? - a different ben
7
我该如何获取当前的种子? - Cina
13
请注意,直到在您的会话中使用了某些随机性之前,.Random.seed才不存在。因此,您应该在其前加上if(!exists(".Random.seed")) set.seed(NULL)来初始化它。 - jan-glx
我想知道在R中,整数和随机数生成器的状态之间是否存在一对一的对应关系?如果是这样的话,那么R似乎最多只能生成2^32个可能的随机数。 - user1539634
如果您能在答案中添加if(!exists(".Random.seed")) set.seed(NULL),那就太好了。这是至关重要的,但很容易被忽视;-) - Christoph

6

Hong在上面的回答很有说服力。 对于快速和简易的解决方案,我只需重复执行整个脚本,直到出现有趣的行为,然后随机选择一个整数,打印出来,然后将其用作种子。 如果我的特定运行具有有趣的行为,我会记录该种子:

eff_seed <- sample(1:2^15, 1)
print(sprintf("Seed for session: %s", eff_seed))
set.seed(eff_seed)

5
为了补充mpettis所给出的答案,如果您不想手动重新执行脚本--在每次迭代中生成新的随机种子--您可以像这样做:
# generate vector of seeds
eff_seeds <- sample(1:2^15, runs)

# perform 'runs' number of executions of your code
for(i in 1:runs) {
    print(sprintf("Seed for this run: %s", eff_seeds[i]))
    set.seed(eff_seeds[i])

    # your code here
    # don't forget to save your outputs somehow
}

变量“runs”是一个正整数,表示您要运行代码的次数。

这样,您可以快速生成大量输出,并为每个迭代生成单独的种子以实现可重复性。


0
> rnorm(5)
[1] -0.17220331 -0.31506128 -0.35264299  0.07259645 -0.15518961
> Seed<-.Random.seed
> rnorm(5)
[1] -0.64965000  0.04787513 -0.14967549  0.12026774 -0.10934254
> set.seed(1234)
> rnorm(5)
[1] -1.2070657  0.2774292  1.0844412 -2.3456977  0.4291247
> .Random.seed<-Seed
> rnorm(5)
[1] -0.64965000  0.04787513 -0.14967549  0.12026774 -0.10934254

-1

这里是尝试解决没有反向getSeed函数的setSeed函数问题的一种方法。我在使用R,如何获取.seed()?上发布了一个类似的问题,大约十二个小时前关闭了,因为它被归类为“重复”...

我已经“黑客式”地用种子内存构建了一个解决方案,需要一个全局变量.random.seed.memory

utils::globalVariables(c(".random.seed.memory"));

时间非常重要,因为我必须使用set.seed来“生成种子”

github.monte = "https://raw.githubusercontent.com/MonteShaffer/";
include.me = paste0(github.monte, "humanVerse/main/humanVerse/R/functions-str.R");  
source(include.me); # trimMe function

include.me = paste0(github.monte, "humanVerse/main/humanVerse/R/functions-random.R");  
source(include.me); # getSeed, setSeed, and so on.

setSeed 函数的行为通常类似于 set.seed,但是除了整数(kind、normal.kind、sample.kind)之外,传递给 set.seed 的任何自定义参数需要在 args.set 中列出,因为 setSeed 中的省略号 ... 用于将参数传递给 initSeed(...),这是一种内部函数,使 setSeedgetSeed 能够正常工作。

我还编写了一个符合C标准的rand()函数,它可以传入最小值、最大值、n值、方法等参数。这是我生成要输入到setSeed并存储在内存中的“整数”的方法。我使用Sys.time()作为默认种子生成的最小/最大值(min = -1*as.integer(Sys.time())max = as.integer(Sys.time()))。sample不是一个好主意,因为它必须创建一个范围内的向量来计算单个值,但它是rand()的一种方法选项,用于输入到initSeed。我发现默认的“high-low”比“floor”略快。

用法

### VERBOSITY is HIGH AT THE MOMENT ###

print("random 5"); rnorm(5);

setSeed(NULL);  # this will automatically call initSeedMemory() if necessary
setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);

print("random 5"); rnorm(5);

setSeed(getSeed()); rnorm(5);

默认情况下,它将种子值存储到全局列表中的一个元素中,称为“last”… 这使您能够跟踪不同的内存种子,具体取决于您正在运行的进程。 在下面的示例中,我特别访问了“last”和“nsim”…第二个存储在内存中的种子...

### VERBOSITY is HIGH AT THE MOMENT ###

initSeedMemory( purge.memory = TRUE);
setSeed(NULL); 
setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);
getSeed(); # accessor to .random.seed.memory
.random.seed.memory;

print("random 5"); rnorm(5);

setSeed(NULL, key="nsim"); rnorm(5);
setSeed(.random.seed.memory$nsim, key="nsim"); rnorm(5);
setSeed(getSeed("nsim"), key="nsim"); rnorm(5);
getSeed("nsim"); # accessor to .random.seed.memory
.random.seed.memory;

print("random 5"); rnorm(5);

setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);
.random.seed.memory;

set.seed(.random.seed.memory$last); rnorm(5);
set.seed(.random.seed.memory$nsim); rnorm(5);

.random.seed.memory;

print("random 5"); rnorm(5);

当然,它可能存在漏洞,如果有任何建议或发现漏洞,我将不胜感激。

-- 2021年2月19日太平洋标准时间上午5点左右 --

当然,也可以传入一个固定的种子。

setSeed(NULL, "nsim"); rnorm(5);  # randomly generated seed under the hood, but stored
setSeed(123, "z5"); rnorm(5);     # you can still fix the seed manually yourself, still stored and accessible in the list
setSeed(getSeed("nsim"), "nsim"); rnorm(5);
setSeed(getSeed("z5"), "z5"); rnorm(5);

如果我们可以将“数字”种子作为rnorm对象的属性附加上去,那就太好了...x=rnorm(5); attributes(x)[["seed"]] = 123; - mshaffer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接