【问题标题】:First two values in .Random.seed are always the same with different set.seed()s.Random.seed 中的前两个值始终与不同的 set.seed() 相同
【发布时间】:2022-01-04 21:54:35
【问题描述】:

序言

我查看了其他问题(123),这些问题描述了set.seed().Random.seed 的使用和功能,但找不到记录的这个特定问题,所以这里是一个问题:

初步观察

当我检查由set.seed(1)set.seed(2) 生成的.Random.seeds 时,我发现前两个元素始终相同(10403624),而其余元素似乎不一样是。请参见下面的示例。

我的问题

  1. 这是预期的吗?
  2. 为什么会这样?
  3. 这会对任何随机模拟产生任何不良后果吗? 可能会基于它吗?

可重现的示例

f <- function(s1, s2){
  
  set.seed(s1)
  r1 <- .Random.seed
  set.seed(s2)
  r2 <- .Random.seed
  
  print(r1[1:3])
  print(r2[1:3])
  
  plot(r1, r2)
  
}

f(1, 2)
#> [1]      10403        624 -169270483
#> [1]       10403         624 -1619336578

reprex package (v2.0.1) 于 2022-01-04 创建

请注意,每个.Random.seed 的前两个元素相同,但其余元素不同。您可以在散点图中看到,正如预期的那样,它只是一个随机的云。

【问题讨论】:

  • 来自?.Random.seed,它说“第一个元素_codes_那种RNG和普通生成器”,所以第一个值不太可能改变,除非改变生成器方法(RNGkind)。对我来说,.Random.seed[2] 表示抽奖次数(所以runif(2) 将第二个整数增加 2),但是当我 set.seed(.) 时,第二个值设置为 624。似乎这是故意的,尽管我找不到它的文档。其余部分包含 RNG 状态。
  • 默认的随机数生成器是“Mersenne-Twister”,其中“‘种子’是一组 624 维的整数”。它在调用 set.seed() 时出现,索引(即第二个值)设置为最大值 624,因此当索引递增以创建下一个随机数时,它从 1 开始。
  • 这些 cmets 是否可以改为答案?
  • 谢谢大家,这太棒了。我想要回答的唯一其他信息是随机过程(例如rnorm())如何使用.Random.seed 来演示为什么前两个值是半常数不会影响模拟结果。
  • 我找不到任何关于随机过程如何实际使用.Random.seed 的机制的信息,因此他们如何知道避免向量中的第一个元素,但如果有人这样做,请随时将其添加到我下面的答案中。

标签: r random random-seed


【解决方案1】:

将来自 @r2evans 和 @Dave2e 的有用 cmets 扩展为答案。

1) .Random.seed[1]

来自?.Random.seed,它说:

".Random.seed 是一个整数向量,其第一个元素编码 一种 RNG 和普通生成器。最低两位小数在 0:(k-1) 其中k 是可用RNG 的数量。数百个 表示正常生成器的类型(从 0 开始),十 千代表离散均匀采样器的类型。”

因此,除非更改生成器方法 (RNGkind),否则第一个值不会更改。

以下是每个可用RNGkinds 的小演示:

library(tidyverse)

# available RNGkind options
kinds <- c(
  "Wichmann-Hill",
  "Marsaglia-Multicarry",
  "Super-Duper",
  "Mersenne-Twister",
  "Knuth-TAOCP-2002",
  "Knuth-TAOCP",
  "L'Ecuyer-CMRG"
)
# test over multiple seeds
seeds <- c(1:3)

f <- function(kind, seed) {
  # set seed with simulation parameters
  set.seed(seed = seed, kind = kind)
  # check value of first element in .Random.seed
  return(.Random.seed[1])
}

# run on simulated conditions and compare value over different seeds
expand_grid(kind = kinds, seed = seeds) %>%
  pmap(f) %>%
  unlist() %>%
  matrix(
    ncol = length(seeds),
    byrow = T,
    dimnames = list(kinds, paste0("seed_", seeds))
  )

#>                      seed_1 seed_2 seed_3
#> Wichmann-Hill         10400  10400  10400
#> Marsaglia-Multicarry  10401  10401  10401
#> Super-Duper           10402  10402  10402
#> Mersenne-Twister      10403  10403  10403
#> Knuth-TAOCP-2002      10406  10406  10406
#> Knuth-TAOCP           10404  10404  10404
#> L'Ecuyer-CMRG         10407  10407  10407

reprex package (v2.0.1) 于 2022-01-06 创建

2) .Random.seed[2]

至少对于默认的"Mersenne-Twister" 方法,.Random.seed[2] 是一个指示随机集中当前位置的索引。来自文档:

“种子”是一组 624 维的 32 位整数加上当前 在该集合中的位置。

当使用种子的随机进程被执行时,它会被更新。但是对于其他方法,文档没有提到类似的内容,并且似乎没有明显的趋势。

下面是.Random.seed[2]set.seed() 之后迭代随机过程的变化示例。

library(tidyverse)

# available RNGkind options
kinds <- c(
  "Wichmann-Hill",
  "Marsaglia-Multicarry",
  "Super-Duper",
  "Mersenne-Twister",
  "Knuth-TAOCP-2002",
  "Knuth-TAOCP",
  "L'Ecuyer-CMRG"
)

# create function to run random process and report .Random.seed[2]
t <- function(n = 1) {
  p <- .Random.seed[2]
  runif(n)
  p
}

# create function to set seed and iterate a random process
f2 <- function(kind, seed = 1, n = 5) {
  
  set.seed(seed = seed,
           kind = kind)

  replicate(n, t())
}

# set simulation parameters
trials <- 5
seeds <- 1:2
x <- expand_grid(kind = kinds, seed = seeds, n = trials) 

# evaluate and report
x %>% 
  pmap_dfc(f2) %>% 
  mutate(n = paste0("trial_", 1:trials)) %>% 
  pivot_longer(-n, names_to = "row") %>% 
  pivot_wider(names_from = "n") %>% 
  select(-row) %>% 
  bind_cols(x[,1:2], .)


#> # A tibble: 14 x 7
#>    kind                  seed    trial_1     trial_2     trial_3 trial_4 trial_5
#>    <chr>                <int>      <int>       <int>       <int>   <int>   <int>
#>  1 Wichmann-Hill            1      23415        8457       23504  2.37e4  2.28e4
#>  2 Wichmann-Hill            2      21758       27800        1567  2.58e4  2.37e4
#>  3 Marsaglia-Multicarry     1 1280795612   945095059    14912928  1.34e9  2.23e8
#>  4 Marsaglia-Multicarry     2 -897583247 -1953114152  2042794797  1.39e9  3.71e8
#>  5 Super-Duper              1 1280795612 -1162609806 -1499951595  5.51e8  6.35e8
#>  6 Super-Duper              2 -897583247   224551822     -624310 -2.23e8  8.91e8
#>  7 Mersenne-Twister         1        624           1           2  3       4     
#>  8 Mersenne-Twister         2        624           1           2  3       4     
#>  9 Knuth-TAOCP-2002         1  166645457   504833754   504833754  5.05e8  5.05e8
#> 10 Knuth-TAOCP-2002         2  967462395   252695483   252695483  2.53e8  2.53e8
#> 11 Knuth-TAOCP              1 1050415712   999978161   999978161  1.00e9  1.00e9
#> 12 Knuth-TAOCP              2  204052929   776729829   776729829  7.77e8  7.77e8
#> 13 L'Ecuyer-CMRG            1 1280795612  -169270483  -442010614  4.71e8  1.80e9
#> 14 L'Ecuyer-CMRG            2 -897583247 -1619336578  -714750745  2.10e9 -9.89e8

reprex package (v2.0.1) 于 2022-01-06 创建

在这里您可以看到,从Mersenne-Twister 方法中,.Random.seed[2] 从最大值624 增加到1 并且增加了随机抽取的大小,并且这set.seed(1)set.seed(2) 是相同的。然而,在其他方法中没有看到相同的趋势。为了说明最后一点,请参见 runif(1).Random.seed[2] 递增 1runif(2) 将其递增 2

# create function to run random process and report .Random.seed[2]
t <- function(n = 1) {
  p <- .Random.seed[2]
  runif(n)
  p
}

set.seed(1, kind = "Mersenne-Twister")
replicate(9, t(1))
#> [1] 624   1   2   3   4   5   6   7   8

set.seed(1, kind = "Mersenne-Twister")
replicate(5, t(2))
#> [1] 624   2   4   6   8

reprex package (v2.0.1) 于 2022-01-06 创建

3) 顺序随机数

因为.Random.seed 的索引或状态(显然对于所有 RNG 方法)根据“随机抽取”的大小(从.Random.seed 生成的随机值的数量)前进,因此可以生成来自同一个种子的同一系列随机数以不同大小的增量。此外,只要在设置相同种子后,在序列中的相同点运行相同的随机过程,似乎就会得到相同的结果。请注意以下示例:

# draw 3 at once
set.seed(1, kind = "Mersenne-Twister")
sample(100, 3, T)
#> [1] 68 39  1

# repeat single draw 3 times
set.seed(1, kind = "Mersenne-Twister")
sample(100, 1)
#> [1] 68
sample(100, 1)
#> [1] 39
sample(100, 1)
#> [1] 1

# draw 1, do something else, draw 1 again
set.seed(1, kind = "Mersenne-Twister")
sample(100, 1)
#> [1] 68
runif(1)
#> [1] 0.5728534
sample(100, 1)
#> [1] 1

reprex package (v2.0.1) 于 2022-01-06 创建

4) 相关随机数

正如我们在上面看到的,在设置相同种子后,两个随机进程在同一点运行,预计会给出相同的结果。但是,即使您对结果的相似程度提供了限制(例如,通过更改 rnorm()mean 或什至通过提供不同的函数),结果似乎仍然在它们各自的范围内完全相关。

# same function with different constraints
set.seed(1, kind = "Mersenne-Twister")
a <- runif(50, 0, 1)

set.seed(1, kind = "Mersenne-Twister")
b <- runif(50, 10, 100)

plot(a, b)

# different functions
set.seed(1, kind = "Mersenne-Twister")
d <- rnorm(50)

set.seed(1, kind = "Mersenne-Twister")
e <- rlnorm(50)

plot(d, e)

reprex package 创建于 2022-01-06 (v2.0.1)

【讨论】:

    猜你喜欢
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 2021-03-06
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多