65

In reference to the statement set.seed(), can I get the seed instead after running some code if I didn't set it explicitly?

I've been re-running some code (interactively / at the console) containing a function that randomises some sample of the input data (the function is part of the kohonen package). After playing with it for some time to see the variety of output (it was an 'unstable' problem), I noticed one result that was pretty interesting. I of course had not used set.seed(), but wondered if I could get the seed after running the code to reproduce the result?

In ?set.seed I see

.Random.seed saves the seed set for the uniform random-number generator

But I don't know how that helps.

zx8754
  • 52,746
  • 12
  • 114
  • 209
a different ben
  • 3,900
  • 6
  • 35
  • 45
  • 1
    The answer by William Dunlap [here](http://r.789695.n4.nabble.com/How-to-obtain-seed-after-generating-random-number-td2336997.html) has some relevant information. – gung - Reinstate Monica Oct 27 '13 at 03:35

5 Answers5

55

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>
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • Thanks Hong. I just added clarification to the question about this relating to working at the console, but you've provided the solution anyway I think. I can still save `.Random.seed` after running the code, right? – a different ben Oct 27 '13 at 11:30
  • 7
    how can I get the current seed? – Cina Jul 03 '15 at 09:12
  • 13
    be aware that .Random.seed does not exist until it some randomness is used in your session. Thus, you should prepend `if(!exists(".Random.seed")) set.seed(NULL)` to initialize it. – jan-glx May 29 '17 at 11:18
  • I wonder if there is any one-to-one correspondence, between the integers and the status of random number generator in R? If there is, it seems to me that then R can generate no more than 2^32 possible random numbers. –  Dec 20 '20 at 11:14
  • It would be great if you could add `if(!exists(".Random.seed")) set.seed(NULL)` to your answer. This is crucial and easily overlooked ;-) – Christoph Apr 27 '22 at 11:40
6

Hong's answer above is robust. For quick and dirty solutions, where I just re-execute a whole script until I get interesting behavior, I randomly pick an integer, print it out, then use that as a seed. If my particular run has interesting behavior, I note that seed:

eff_seed <- sample(1:2^15, 1)
print(sprintf("Seed for session: %s", eff_seed))
set.seed(eff_seed)
mpettis
  • 3,222
  • 4
  • 28
  • 35
5

To add to the answer mpettis gave, if you don't want to re-execute the script manually--generating new random seeds each iteration--you could do something like this:

# generate vector of seeds
eff_seeds <- sample(1:2^15, runs)

# perform 'runs' number of executions of your code
for(i in 1:runs) {
    print(sprintf("Seed for this run: %s", eff_seeds[i]))
    set.seed(eff_seeds[i])

    # your code here
    # don't forget to save your outputs somehow
}

Where the variable 'runs' is a positive integer indicating the number of times you want to run your code.

This way you can generate a lot of output rapidly and have individual seeds for each iteration for reproducibility.

Andrew
  • 301
  • 3
  • 3
0
> rnorm(5)
[1] -0.17220331 -0.31506128 -0.35264299  0.07259645 -0.15518961
> Seed<-.Random.seed
> rnorm(5)
[1] -0.64965000  0.04787513 -0.14967549  0.12026774 -0.10934254
> set.seed(1234)
> rnorm(5)
[1] -1.2070657  0.2774292  1.0844412 -2.3456977  0.4291247
> .Random.seed<-Seed
> rnorm(5)
[1] -0.64965000  0.04787513 -0.14967549  0.12026774 -0.10934254
heeseon
  • 23
  • 5
-1

Here is an attempt to fix the problem of not having an inverse getSeed function for the setSeed function. I posted a similar question about twelve hours ago on Using R, how to get.seed()? which was closed as it is classified a "duplicate" ...

I have "hacked" together a solution with a seed memory which requires a global variable .random.seed.memory.

utils::globalVariables(c(".random.seed.memory"));

Timings are important since I have to "generate a seed" using set.seed

github.monte = "https://raw.githubusercontent.com/MonteShaffer/";
include.me = paste0(github.monte, "humanVerse/main/humanVerse/R/functions-str.R");  
source(include.me); # trimMe function

include.me = paste0(github.monte, "humanVerse/main/humanVerse/R/functions-random.R");  
source(include.me); # getSeed, setSeed, and so on.

The function setSeed behaves generally like set.seed but any custom parameters passed to set.seed beyond the integer (kind, normal.kind, sample.kind) need to be listed in args.set as the ellipses ... for setSeed are used to pass parameters to initSeed(...) an internal function that enables setSeed and getSeed to work.

I also wrote a C-standard rand() function that passes in a min, max, n, method, and so on. This is how I generate an "integer" to feed the setSeed and store in memory. I use Sys.time() as min/max for a default seed generation (min = -1*as.integer(Sys.time()) and max = as.integer(Sys.time()) ). sample is a bad idea as it has to create a vector in the range to compute a single value, but it is an method option of rand() which feeds initSeed. The default "high-low" I found to be slightly faster than "floor".

USAGE

### VERBOSITY is HIGH AT THE MOMENT ###

print("random 5"); rnorm(5);

setSeed(NULL);  # this will automatically call initSeedMemory() if necessary
setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);

print("random 5"); rnorm(5);

setSeed(getSeed()); rnorm(5);

By default it stores the seed value to an element in the global list called "last" ... This enables you to keep track of different memory seeds depending on the processes you are running. In the example below I access "last" specifically and "nsim" ... a second seed stored in memory ...

### VERBOSITY is HIGH AT THE MOMENT ###

initSeedMemory( purge.memory = TRUE);
setSeed(NULL); 
setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);
getSeed(); # accessor to .random.seed.memory
.random.seed.memory;

print("random 5"); rnorm(5);

setSeed(NULL, key="nsim"); rnorm(5);
setSeed(.random.seed.memory$nsim, key="nsim"); rnorm(5);
setSeed(getSeed("nsim"), key="nsim"); rnorm(5);
getSeed("nsim"); # accessor to .random.seed.memory
.random.seed.memory;

print("random 5"); rnorm(5);

setSeed(.random.seed.memory$last); rnorm(5);
setSeed(getSeed()); rnorm(5);
.random.seed.memory;

set.seed(.random.seed.memory$last); rnorm(5);
set.seed(.random.seed.memory$nsim); rnorm(5);

.random.seed.memory;

print("random 5"); rnorm(5);

Of course, it may have bugs, and I would appreciate any suggestions or bugs found.

-- 02/19/2021 about 5AM in PST --

Of course, the ability to pass in a fixed seed is also possible.

setSeed(NULL, "nsim"); rnorm(5);  # randomly generated seed under the hood, but stored
setSeed(123, "z5"); rnorm(5);     # you can still fix the seed manually yourself, still stored and accessible in the list
setSeed(getSeed("nsim"), "nsim"); rnorm(5);
setSeed(getSeed("z5"), "z5"); rnorm(5);
mshaffer
  • 959
  • 1
  • 9
  • 19
  • It would be nice if we could append the "numeric" seed as an attribute of the `rnorm` object ... ```x=rnorm(5); attributes(x)[["seed"]] = 123;``` – mshaffer Feb 20 '21 at 08:57