0Pricing
R Academy · 课时

set.seed() 与可复现性

使用 set.seed() 确保多次运行生成可复现的随机数

set.seed() 与可复现性 是 CoddyKit 上的免费 R Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。

为什么可复现性很重要

随机数生成是伪随机的:它由一个起始值设定种子的确定性算法生成。设置 seed 可使模拟具有可复现性——相同的代码始终产生相同的结果,这对调试、发表和教学都至关重要。

# Without set.seed: different every run
runif(3)  # e.g., 0.21, 0.57, 0.89 (changes each run)
runif(3)  # different again!

# With set.seed: always identical
set.seed(42)
runif(3)  # always: 0.9148060 0.9370754 0.2861395

set.seed(42)  # reset seed
runif(3)  # exactly the same three numbers again

cat('set.seed() is your reproducibility guarantee')

set.seed() 的工作机制

set.seed(n) 初始化随机数生成器(RNG)的状态。任何正整数都可以使用。seed 决定从此开始直到再次重置 seed 之前的整个随机数序列。请使用固定数值以保证可复现性。

# Different seeds give different sequences
set.seed(1)
seq1 <- rnorm(5)

set.seed(99)
seq2 <- rnorm(5)

print(seq1)
print(seq2)
identical(seq1, seq2)  # FALSE

# Same seed always gives same sequence
set.seed(1)
seq1_again <- rnorm(5)
identical(seq1, seq1_again)  # TRUE

# Common seed choices
set.seed(123)   # popular convention
set.seed(2024)  # use year for temporal clarity

RNGkind():RNG 算法

RNGkind() 显示(或设置)RNG 算法。R 的默认算法是 Mersenne-Twister,正态分布方法是 Inversion。算法会影响随机数序列,因此要实现完全可复现,应同时记录 seed 和 RNGkind。

# Check current RNG settings
RNGkind()
# [1] 'Mersenne-Twister' 'Inversion' 'Rejection'
# [1] kind, normal.kind, sample.kind

# Set explicitly for maximum reproducibility
RNGkind('Mersenne-Twister', 'Inversion', 'Rejection')
set.seed(42)
runif(3)

# Alternative RNG algorithms (rarely needed)
# RNGkind('L'Ecuyer-CMRG') # for parallel RNG
# RNGkind('Super-Duper')   # older algorithm

cat('Default Mersenne-Twister has period 2^19937 - 1')

检查 .Random.seed

.Random.seed 是一个存储完整 RNG 状态的全局整数向量。每次生成随机数后,它都会自动更新。您可以保存并恢复它,以便从任意位置重放随机数序列。

set.seed(42)
# .Random.seed is created in .GlobalEnv after first use
length(.Random.seed)  # 626 integers for Mersenne-Twister
.Random.seed[1]       # encodes RNG type

# Generate one number (state advances)
x1 <- runif(1)
state_after <- .Random.seed

# Generate another
x2 <- runif(1)

# Restore state to after x1
.Random.seed <<- state_after
x2_replay <- runif(1)

identical(x2, x2_replay)  # TRUE - we replayed the state
cat('x2:', x2, 'x2_replay:', x2_replay)

保存和恢复 RNG 状态

请在一段代码运行前保存 RNG 状态,之后再恢复它,即可精确重放这段代码。需要从序列中途继续时,这比 set.seed() 更灵活。

set.seed(100)
# Generate some random numbers first
runif(10)

# Save current state
saved_state <- .Random.seed

# Generate block of interest
block1 <- rnorm(5)
print(block1)

# ... later, restore and replay
.Random.seed <<- saved_state
block1_replay <- rnorm(5)

identical(block1, block1_replay)  # TRUE!
cat('RNG state saved and restored successfully')

使用 L'Ecuyer-CMRG 进行并行 RNG

使用并行计算时,每个进程都需要一个独立的随机数生成器流。L'Ecuyer-CMRG生成器为并行工作进程提供较长且互不重叠的随机数流,确保不同核心上的结果彼此独立。

# Set up L'Ecuyer-CMRG for parallel use
RNGkind('L\'Ecuyer-CMRG')
set.seed(42)

# Each parallel worker gets its own stream
# (parallel package handles this automatically)
# library(parallel)
# cl <- makeCluster(4)
# clusterSetRNGStream(cl, iseed = 42)

# Generate numbers with this generator
samples <- rnorm(5)
print(samples)

# Reset to default Mersenne-Twister
RNGkind('Mersenne-Twister', 'Inversion', 'Rejection')
cat('L\'Ecuyer-CMRG: safe for parallel simulation')

函数调用中的种子

在函数内部设置种子不会影响函数返回后调用者的随机数生成器状态——因为函数中的种子调用会修改全局的 .Random.seed。对于可复用函数,请明确管理种子。

# Function that optionally accepts a seed
simulate_data <- function(n, seed = NULL) {
  if (!is.null(seed)) set.seed(seed)
  list(
    x = rnorm(n),
    y = rnorm(n)
  )
}

# Reproducible call
result1 <- simulate_data(5, seed = 42)
result2 <- simulate_data(5, seed = 42)
identical(result1$x, result2$x)  # TRUE

# Without seed: different each time
result3 <- simulate_data(5)
result4 <- simulate_data(5)
identical(result3$x, result4$x)  # FALSE

可复现的抽样

sample.kind 参数专门影响 sample()。从 R 3.6.0 开始,默认值改为 'Rejection',以获得更好的均匀性——在可复现的工作流程中请使用此设置。

# R 3.6+ default sample kind
RNGkind(sample.kind = 'Rejection')  # default
set.seed(42)
sample(1:10, 5)
# [1] 1 5 10 8 2  (with Rejection)

# Old behavior (R < 3.6) for legacy code
RNGkind(sample.kind = 'Rounding')
set.seed(42)
sample(1:10, 5)
# Different result!

# Best practice: reset to modern defaults
RNGkind('Mersenne-Twister', 'Inversion', 'Rejection')
set.seed(42)
sample(1:10, 5)

记录随机性

可复现研究的良好实践是:记录您的 R 版本、种子值和 RNGkind。使用 sessionInfo() 完整记录环境信息。在脚本注释或配置文件中记录种子。

# Reproducibility header for analysis scripts:
# R version: R.version$version.string
# Seed: 42
# RNGkind: Mersenne-Twister / Inversion / Rejection

# Capture R version
R.version$version.string

# Capture full session info
# sessionInfo()  # shows all packages and versions

# In RMarkdown, set seed in setup chunk:
# ```{r setup}
# knitr::opts_chunk$set(echo = TRUE)
# set.seed(42)
# ```

# This ensures all chunks share the same RNG state
set.seed(42)
cat('R version:', R.version$version.string, '\n')
cat('Seed: 42, RNGkind: Mersenne-Twister')

蒙特卡洛研究中的种子

在大型模拟研究中,请使用一个主种子来生成每次重复所用的种子。这样既能让每次重复单独实现可复现,又能使整体设计保持确定性。

# Generate per-replicate seeds from a master seed
set.seed(2024)
n_replicates <- 5
replicate_seeds <- sample.int(1e6, n_replicates)
print(replicate_seeds)

# Each replicate uses its own seed
run_replicate <- function(rep_id) {
  set.seed(replicate_seeds[rep_id])
  mean(rnorm(1000))  # estimate with this seed
}

results <- sapply(seq_len(n_replicates), run_replicate)
print(round(results, 4))

# Any single replicate can be re-run independently:
set.seed(replicate_seeds[3])
mean(rnorm(1000))  # exactly matches results[3]

使用 withr 测试随机性

withr 程序包提供了 with_seed(seed, expr),它会临时设置种子、计算表达式,然后恢复原始随机数生成器状态——非常适合测试,且不会污染全局状态。

# withr::with_seed - restore RNG state automatically
# library(withr)
# result <- with_seed(42, rnorm(5))

# Simulation without withr (manual state save)
old_seed <- if (exists('.Random.seed')) .Random.seed
old_kind <- RNGkind()

set.seed(42)
result <- rnorm(5)

# Restore
if (!is.null(old_seed)) .Random.seed <<- old_seed
cat('Result:', result, '\n')
cat('Caller\'s RNG state preserved')

# set.seed in tests ensures deterministic assertions:
set.seed(1)
stopifnot(round(rnorm(1), 6) == round(-0.6264538, 6))

快速检查

测试您对 R 中随机数生成器可复现性的理解。

回顾:种子与可复现性

要点: set.seed(n) 可使包含随机操作的代码实现可复现。RNGkind() 显示或设置算法——请同时记录种子和算法类型。.Random.seed 存储完整的随机数生成器状态,并且可以保存和恢复。对于并行计算,请使用 L'Ecuyer-CMRG。在函数中接受 seed 参数。在大型模拟中,使用由主种子生成的每次重复专用种子。

# Reproducibility checklist:
# 1. Set seed at script top
set.seed(42)

# 2. Document RNGkind
RNGkind()  # Mersenne-Twister / Inversion / Rejection

# 3. Save RNG state if needed
saved <- .Random.seed

# 4. For functions, accept seed argument
my_sim <- function(n, seed = NULL) {
  if (!is.null(seed)) set.seed(seed)
  rnorm(n)
}

# 5. For parallel: use L'Ecuyer-CMRG
# RNGkind('L\'Ecuyer-CMRG'); set.seed(42)

cat('Reproducibility = trust in your results')

常见问题解答

「set.seed() 与可复现性」课时是免费的吗?

是的 — 「set.seed() 与可复现性」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。

「set.seed() 与可复现性」这节课中我会学到什么?

使用 set.seed() 确保多次运行生成可复现的随机数 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「set.seed() 与可复现性」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 R Academy 课中编写并运行代码吗?

能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. set.seed() 与可复现性
  2. 生成随机分布
  3. 蒙特卡洛模拟基础
  4. R 中的 Bootstrap 重抽样
← 返回 R Academy