.Random.seed 中的前两个值对于不同的 set.seed() 总是相同的

First two values in .Random.seed are always the same with different set.seed()s

前言

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

初步观察

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

我的问题

  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 的前两个元素相同,但其余部分不同。您可以在散点图中看到它只是预期的随机云。

将@r2evans 和@Dave2e 的有用评论扩展为答案。

1) .Random.seed[1]

来自?.Random.seed,它说:

".Random.seed is an integer vector whose first element codes the kind of RNG and normal generator. The lowest two decimal digits are in 0:(k-1) where k is the number of available RNGs. The hundreds represent the type of normal generator (starting at 0), and the ten thousands represent the type of discrete uniform sampler."

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

下面是每个可用 RNGkind 的一个小演示:

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]是一个索引,表示当前在随机集中的位置。来自文档:

The ‘seed’ is a 624-dimensional set of 32-bit integers plus a current position in that set.

这会在执行使用种子的随机过程时更新。然而,对于其他方法,文档没有提到类似的内容,并且似乎没有以相同的方式出现明显的趋势。

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

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 draw' 的大小(从 .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 (v2.0.1)

创建于 2022-01-06