在R中关于set.seed()的问题

22

我知道set.seed()做什么以及何时使用它,但我仍有许多关于该函数的问题。以下是几个问题:

  1. 如果您在会话中较早地调用了set.seed(),是否有可能将其“重置”为“更随机”的内容? 这是必要的吗?
  2. 是否有办法查看R当前正在使用的种子(seed)?
  3. 是否有一种方法可以使set.seed()允许输入字母数字混合种子,就像人们可以在random.org网站输入的那样(确保您在高级模式下,并查看表单的“第3部分”)?

4
  1. 我认为这并不必要。
  2. ?.Random.seed(虽然有点复杂,但也许会有其他人回答)。
- Ben Bolker
2
阅读 ?RNG 可以得到大部分答案。 - Andrie
5个回答

18

只是为了好玩:

set.seed.alpha <- function(x) {
  require("digest")
  hexval <- paste0("0x",digest(x,"crc32"))
  intval <- type.convert(hexval) %% .Machine$integer.max
  set.seed(intval)
}

所以你可以这样做:

set.seed.alpha("hello world")

(实际上x可以是任何R对象,而不仅仅是字母数字字符串)


不错的“只是为了好玩”的回答。实际上,我想创建一个种子向量以在函数中使用。因此,假设我正在基于名为village.names的对象创建种子,我可能会做更多类似这样的事情:hexval <- paste0("0x", sapply(village.names, digest, "crc32")); intval <- type.convert(hexval) %% .Machine$integer.max 以生成要传递给另一个函数的种子列表。感谢迄今为止提供的所有建议! - A5C1D2H2I1M1N2O1R2T1

15
如果您将种子设置为类似于时间纪元的最终数字,那么这是可能的,但实际上并不必要。 PRNG 的预期用途是在会话开始时仅设置一次种子,并使用从此生成的连续变量。如果采用不同的方法,则无法享受 R RNG 具有的各种良好的理论和经验性质。
但我不确定您是否真正理解 set.seed 的目的。它并不是为了让您获得“更随机”的数字。如果您正在进行某种应用程序,R PRNG 不足以满足您的需求(例如,如果您需要加密随机性),那么您可以通过某些替代方法生成所有随机数并直接使用它们。 set.seed 的真正目的是使用 RNGs 产生可重现性结果。如果您使用相同的随机数生成序列开始相同的分析,并将种子设置为相同的值,则始终会获得相同的结果。这对于调试和其他人审查您的结果非常有帮助。
要使用纪元时间,请执行以下操作:
t <- as.numeric(Sys.time())
seed <- 1e8 * (t - floor(t))
set.seed(seed); print(seed)

我明白set.seed()的作用是为了使结果可复现等方面。我关注的是,假设我执行set.seed(123); a = sample(300, 30); b = sample(300, 30),但我只想让a“可复现”——我希望每次运行时得到的b结果不同。对我来说,这意味着在执行ab的代码之间,我需要以某种方式重置种子。 - A5C1D2H2I1M1N2O1R2T1
6
好的,尝试像这样使用as.numeric(Sys.time())-> t; set.seed((t - floor(t)) * 1e8 -> seed); print(seed)这样的代码通常可以有效地实现大多数目的。 - Fhnuzoag
2
Fhnuzoag 应该是一个答案,而不是评论,我个人认为。 - JD Long
@JDLong,与rm(.Random.seed, envir=globalenv())相比,Fhnuzoag的解决方案除了能够查看新的随机种子外,还有什么优势吗?在我有限的R使用中,我没有使用过globalenv(),所以我不太清楚我在做什么。但我可以理解我在使用Fhnuzoag的解决方案。我之所以问这个问题,是因为.Random.seed的帮助文件指出它不应该被用户更改,但在其示例中建议使用rm(.Random.seed) - A5C1D2H2I1M1N2O1R2T1

7

针对您的第三个问题,在TeachingDemos包中有一个char2seed函数,可以将字符字符串(字母数字)转换为整数,并默认使用它来设置新种子。这个想法是让学生可以使用他们的名字(或某些组合/子集的名字)作为种子,以便每个学生都能得到不同的数据集,但老师可以重现每个学生的数据集。


感谢您的建议。我在最初的问题中没有明确说明,但实际上我需要根据一个字符向量创建种子向量。看起来您的函数无法做到这一点,我是正确的吗?顺便说一句,这是一个很棒的软件包。 - A5C1D2H2I1M1N2O1R2T1
1
当前版本仅生成1个种子,而不是向量(由于上述目的而设计),其中硬编码为[[1]]。 但是,它可以进行修改(使用sapply而不是抓取strsplit结果的第一个元素)以与向量一起使用,或者可以使用sapplymapplyVectorizechar2seed一起使用,从向量输入中获得向量结果。 - Greg Snow

3

针对问题2的答案,请首先查看帮助页面?RNGkind

找到当前使用的随机数生成器种类:

RNGkind()
# [1] "Mersenne-Twister" "Inversion" 

Mersenne Twister是默认的随机数生成器。
从帮助页面中可以得知:
“Mersenne-Twister”:源自Matsumoto和Nishimura(1998)的一种扭曲GFSR,其周期为2^19937-1,并且在623个连续维度上具有等分布性(整个周期内)。 "种子"是一个624维的32位整数集合和该集合中的当前位置。
要找到当前使用的种子,您需要先调用随机数生成器。
runif(1, 0, 1)                                                                                                                                                  
# [1] 0.9834062                                                                                                                                                      
.Random.seed
# [Gives a 626 length vector]

调用set.seed(一些整数),然后是.Random.seed ,如果您使用相同的some_integer,将总是给出相同的626长度向量。换句话说,在使用Mersenne Twister的情况下,626长度向量仅由some_integer 确定。
当然,将 set.seed 运行到某个固定值将为随后调用随机数例程提供相同的值。在实践中,这是它的主要用途,以获得可重复性。例如:
set.seed(1)
runif(5, 0, 1)
# [1] 0.2655087 0.3721239 0.5728534 0.9082078 0.2016819
rnorm(1, 0, 1)
# [1] 1.272429
set.seed(1)
runif(5, 0, 1)
# [1] 0.2655087 0.3721239 0.5728534 0.9082078 0.2016819
rnorm(1, 0, 1)
# [1] 1.272429

所有R语言中基本的数字生成器代码都在源代码文件src/main/RNG.c中。虽然是用C语言编写的,但相当容易理解。

1

我和问题1一样遇到了同样的问题。然后我想,我可以通过在循环中重置种子来解决:

set.seed(123)
x<- rnorm(10,1,1)
set.seed(null)

在每次循环结束时,种子都会被删除。这对我有效。

感谢您的回答。更常见/正统的方法是 rm(.Random.seed, envir=globalenv()),这在 ?.Random.seed 的帮助文件中提到...我在提出这个问题后才找到它 :-) - A5C1D2H2I1M1N2O1R2T1
“set.seed(null)” 对我没有起作用。是否有其他方法可以重置种子值或将其置为空? - mockash

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