11

Is this the only way to 'unseed' the random number generator:

np.random.seed(int(time.time()))

If you have some code that you want to be repeatable (e.g. a test) in a loop with other code that you want to be random each loop, how do you 'reset' the seed to random number generator after setting it?

The following code illustrates the issue:

import numpy as np

def test():
    np.random.seed(2)
    print("Repeatable test:", [np.random.randint(10) for i in range(3)])

for i in range(4):
    print("Random number:", np.random.randint(10))
    test()

Random number: 8
Repeatable test: [8, 8, 6]
Random number: 2
Repeatable test: [8, 8, 6]
Random number: 2
Repeatable test: [8, 8, 6]
Random number: 2
Repeatable test: [8, 8, 6]

Desired result: I want random number to be random each loop.

I am happy to import the time module if this is the only way to do it but I thought there might be a simpler, more robust way.

(You can't get the current seed according to this post)

Bill
  • 10,323
  • 10
  • 62
  • 85
  • dont count on random seed for repeatable randomness ... even using the same seed you will get different outcomes on different OS and between different python versions ... (not an answer i know ...) – Joran Beasley Sep 27 '18 at 20:56
  • You can set the seed once (at the beginning of your program, outside of your function), and then use a random number generator to set the seed in each run. Save the seed that's randomly generated and, assuming all else is equal, you should be able to recreate any run. – pault Sep 27 '18 at 20:57
  • The seed doesn't really change the random number generator; each call to `randint` effectively returns the next number in a predetermined sequence. Setting the seed just jumps to a different position in that sequence. – chepner Sep 27 '18 at 20:57
  • Thanks @JoranBeasley but I am not counting on repeatable randomness across different platforms. That is not the issue I have. – Bill Sep 27 '18 at 21:01
  • Thanks @pault that is a neat idea! – Bill Sep 27 '18 at 21:01
  • 2
    From the documentation: "The functions supplied by this module are actually bound methods of a hidden instance of the random.Random class. You can instantiate your own instances of Random to get generators that don’t share state. This is especially useful for multi-threaded programs, creating a different instance of Random for each thread, and using the jumpahead() method to make it likely that the generated sequences seen by each thread don’t overlap." – chepner Sep 27 '18 at 21:02
  • 1
    @chepner: Different `random` - you're looking at the stdlib `random`, not `numpy.random`. For `numpy.random`, the situation is very similar, but with a hidden instance of `numpy.random.RandomState`. – user2357112 Sep 27 '18 at 21:11
  • @user2357112 Oops. :) – chepner Sep 27 '18 at 21:55

4 Answers4

17

You're going down the wrong path. Instead of trying to unseed the global RNG used by numpy.random, use a separate RNG for the parts that need to be repeatable. This RNG can have a completely independent state from the numpy.random default RNG:

def test():
    rng = numpy.random.RandomState(2)
    print("Repeatable test:", [rng.randint(10) for i in range(3)])

While it is technically possible to save and restore the state of the global numpy.random RNG, it is a very specialized operation and rarely a good idea. It may be useful, for example, if you're debugging a piece of code and you want to "rewind" the random state after jumping backward through the code, though you need to save the state in advance, and it won't rewind any other random number generators:

# Don't abuse this.
state = numpy.random.get_state()
do_stuff()
numpy.random.set_state(state)
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • https://numpy.org/doc/stable/reference/random/legacy.html `RandomState()` is actually legacy now - how would you replace it? – jtlz2 Aug 10 '21 at 09:18
  • @jtlz2: Use the new [`Generator` API](https://numpy.org/doc/stable/reference/random/generator.html) instead of `RandomState`: `rng = numpy.random.default_rng(whatever_seed)`, and remember that this is a new, redesigned API, so a bunch of methods have different names or work differently from the old methods that provided their functionality. – user2357112 Aug 10 '21 at 09:41
  • Also the shown `numpy.random.get_state()` seems to be legacy in the sense that it does not fit to the style of the new Generator API, where you can have several RNGs each with a separate state. – notfancy May 12 '22 at 09:37
5

You can instantiate your own Random object.

myrandom = random.Random(myseed)

The random module manages its own instance of Random, which will be unaffected by changes made to myrandom.

Artem Bernatskyi
  • 4,185
  • 2
  • 26
  • 35
1

random. seed ( a=None, version=2 ) Initialize the random number generator. If a is omitted or None, the current system time is used. If randomness sources are provided by the operating system, they are used instead of the system time (see the os.urandom() function for details on availability)

random.seed(None)

worked for me

Python 3.8 docs

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 04 '21 at 16:19
0

Another way to do this

  • You could generate random seeds for each loop respectively, but you would get the same seed value after the first iteration if you generate them inside the loop.
  • To avoid the seeds in each loop from being all the same, just generate different seeds outside the loop beforehand.
import numpy as np

def test():
    np.random.seed(2)
    print("Repeatable test:", [np.random.randint(10) for i in range(3)])

n_loop = 4
max_rand_int = 1000*n_loop # i think this is enough
seeds = np.random.randint(max_rand_int, size=n_loop) # make list of seeds
for i in range(n_loop):
    print("Random number:", np.random.randint(10))
    test()
    seed = seeds[i]
    np.random.seed(seed)
johnnyasd12
  • 636
  • 7
  • 11