Fixing Set.Seed for an Entire Session

Fixing set.seed for an entire session

There are several options, depending on your exact needs. I suspect the first option, the simplest is not sufficient, but my second and third options may be more appropriate, with the third option the most automatable.

Option 1

If you know in advance that the function using/creating random numbers will always draw the same number, and you don't reorder the function calls or insert a new call in between existing ones, then all you need do is set the seed once. Indeed, you probably don't want to keep resetting the seed as you'll just keep on getting the same set of random numbers for each function call.

For example:

> set.seed(1)
> sample(10)
[1] 3 4 5 7 2 8 9 6 10 1
> sample(10)
[1] 3 2 6 10 5 7 8 4 1 9
>
> ## second time round
> set.seed(1)
> sample(10)
[1] 3 4 5 7 2 8 9 6 10 1
> sample(10)
[1] 3 2 6 10 5 7 8 4 1 9

Option 2

If you really want to make sure that a function uses the same seed and you only want to set it once, pass the seed as an argument:

foo <- function(...., seed) {
## set the seed
if (!missing(seed))
set.seed(seed)
## do other stuff
....
}

my.seed <- 42
bar <- foo(...., seed = my.seed)
fbar <- foo(...., seed = my.seed)

(where .... means other args to your function; this is pseudo code).

Option 3

If you want to automate this even more, then you could abuse the options mechanism, which is fine if you are just doing this in a script (for a package you should use your own options object). Then your function can look for this option. E.g.

foo <- function() {
if (!is.null(seed <- getOption("myseed")))
set.seed(seed)
sample(10)
}

Then in use we have:

> getOption("myseed")
NULL
> foo()
[1] 1 2 9 4 8 7 10 6 3 5
> foo()
[1] 6 2 3 5 7 8 1 4 10 9
> options(myseed = 42)
> foo()
[1] 10 9 3 6 4 8 5 1 2 7
> foo()
[1] 10 9 3 6 4 8 5 1 2 7
> foo()
[1] 10 9 3 6 4 8 5 1 2 7
> foo()
[1] 10 9 3 6 4 8 5 1 2 7

After setting seed, for how long or how many chunks of code will that seed be effective for?

The seed defines the state of the random number generator for all times (in this session). The only thing that can happen is that someone resets it with set.seed(NULL) in which case the current time is used as the new seed. Unfortuantely that can also happen in some package you do not have control about.

Addition: It can also happen that the package changes the kind of RNG used, in which case the seed will also no longer have effect.

Reasons for using the set.seed function

The need is the possible desire for reproducible results, which may for example come from trying to debug your program, or of course from trying to redo what it does:

These two results we will "never" reproduce as I just asked for something "random":

R> sample(LETTERS, 5)
[1] "K" "N" "R" "Z" "G"
R> sample(LETTERS, 5)
[1] "L" "P" "J" "E" "D"

These two, however, are identical because I set the seed:

R> set.seed(42); sample(LETTERS, 5)
[1] "X" "Z" "G" "T" "O"
R> set.seed(42); sample(LETTERS, 5)
[1] "X" "Z" "G" "T" "O"
R>

There is vast literature on all that; Wikipedia is a good start. In essence, these RNGs are called Pseudo Random Number Generators because they are in fact fully algorithmic: given the same seed, you get the same sequence. And that is a feature and not a bug.

R set.seed() 's scope

set.seed is indeed global. But note this from the example in ?set.seed:

## If there is no seed, a "random" new one is created:
rm(.Random.seed); runif(1); .Random.seed[1:6]

This means you can call rm(.Random.seed, envir=.GlobalEnv) either at the end of your function or after you call the function to decouple the rest of the program from the call to set.seed in the function.

To see this in action, run the following code in two different R sessions. The outputs should be the same in both sessions. Then re-run the code again in two new R sessions with the rm line uncommented. You'll see the output in the two new sessions now differ, indicating that the call to set.seed in the function hasn't transferred the reproducibility to the main program.

subfun <- function() {
set.seed(100)
rnorm(1)
#rm(.Random.seed, envir=.GlobalEnv)
}

subfun()
#[1] -0.5022

rnorm(1)
# [1] 0.1315

Can I get.seed() somehow?

If you didn't keep the seed, there's no general way to "roll back" the random number generator to a previous state after you've observed a random draw. Going forward, what you may want to do is save the value of .Random.seed along with the results of your computations. Something like this.

x <- .Random.seed
result <- <your code goes here>
attr(result, "seed") <- x

Then you can reset the PRNG as follows; result2 should be the same as result.

.Random.seed <- attr(result, "seed")
result2 <- <your code goes here>


Related Topics



Leave a reply



Submit