0Pricing
R Academy · Lesson

set.seed() and Reproducibility

Ensure reproducible random number generation across runs with set.seed().

set.seed() and Reproducibility is a free R Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Reproducibility Matters

Random number generation is pseudo-random: a deterministic algorithm seeded by a starting value. Setting the seed makes your simulations reproducible — the same code always produces the same results, essential for debugging, publishing, and teaching.

# 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() Mechanics

set.seed(n) initializes the random number generator (RNG) state. Any positive integer works. The seed determines the entire future sequence of random numbers until the seed is reset. Use a fixed number for reproducibility.

# 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 Algorithm

RNGkind() shows (or sets) the RNG algorithm. R's default is Mersenne-Twister with normal distribution method Inversion. The algorithm affects the sequence, so document both seed and RNGkind for full reproducibility.

# 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')

Inspecting .Random.seed

.Random.seed is a global integer vector storing the full RNG state. It's automatically updated after each random draw. You can save and restore it to replay a sequence from any point.

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)

Saving and Restoring RNG State

Save the RNG state before a block of code, then restore it later to exactly replay that block. This is more flexible than set.seed() when you need to resume mid-sequence.

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')

Parallel RNG with L'Ecuyer-CMRG

When using parallel computing, each process needs an independent RNG stream. The L'Ecuyer-CMRG generator provides long non-overlapping streams for parallel workers, ensuring results are independent across cores.

# 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')

Seed in Function Calls

Setting a seed inside a function doesn't affect the caller's RNG state after the function returns — because the function's seed call modifies the global .Random.seed. Be explicit about seed management in reusable functions.

# 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

Reproducible Sampling

The sample.kind argument to RNGkind() affects sample() specifically. Since R 3.6.0, the default changed to 'Rejection' for better uniformity — use this in reproducible workflows.

# 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)

Documenting Randomness

Good practice for reproducible research: document your R version, seed value, and RNGkind. Use sessionInfo() for full environment capture. Record seeds in script comments or a configuration file.

# 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')

Seeds in Monte Carlo Studies

In large simulation studies, use a single master seed to generate per-replicate seeds. This makes each replicate individually reproducible while keeping the overall design deterministic.

# 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]

Testing Randomness with withr

The withr package provides with_seed(seed, expr) which temporarily sets a seed, evaluates the expression, then restores the original RNG state — perfect for tests without polluting global state.

# 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))

Quick Check

Test your understanding of RNG reproducibility in R.

Recap: Seed and Reproducibility

Key takeaways: set.seed(n) makes random code reproducible. RNGkind() shows/sets the algorithm — document both seed and kind. .Random.seed stores the full RNG state and can be saved/restored. For parallel computing, use L'Ecuyer-CMRG. In functions, accept a seed parameter. Use per-replicate seeds generated from a master seed in large simulations.

# 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')

Frequently asked questions

Is the “set.seed() and Reproducibility” lesson free?

Yes — the full text of “set.seed() and Reproducibility” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

What will I learn in “set.seed() and Reproducibility”?

Ensure reproducible random number generation across runs with set.seed(). You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start R Academy?

No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “set.seed() and Reproducibility” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this R Academy lesson?

Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. set.seed() and Reproducibility
  2. Generating Random Distributions
  3. Monte Carlo Simulation Basics
  4. Bootstrap Resampling in R
← Back to R Academy