web-dev-qa-db-fra.com

Comment puis-je récupérer la graine actuelle du générateur de nombres aléatoires de NumPy?

Les éléments suivants importent NumPy et définissent la graine.

import numpy as np
np.random.seed(42)

Cependant, je ne suis pas intéressé par la mise en place de la graine mais plutôt par sa lecture. random.get_state() ne semble pas contenir la graine. La documentation ne montre pas une réponse évidente.

Comment puis-je récupérer la graine actuelle utilisée par numpy.random, en supposant que je ne l'aie pas définie manuellement?

Je veux utiliser la graine actuelle pour la prochaine itération d'un processus.

38
Mast

La réponse courte est que vous ne pouvez simplement pas (du moins pas en général).

Le Mersenne Twister RNG utilisé par numpy a 219937-1 états internes possibles, alors qu'un seul entier de 64 bits n'en a que 264 valeurs possibles. Il est donc impossible de mapper chaque état RNG sur une graine entière unique.

Vous pouvez obtenir et définir directement l'état interne du générateur de RNG en utilisant np.random.get_state et np.random.set_state . La sortie de get_state est un tuple dont le deuxième élément est un tableau (624,) d'entiers 32 bits. Ce tableau a plus que suffisamment de bits pour représenter chaque état interne possible du RNG (2624 * 32 > 219937-1).

Le tuple renvoyé par get_state peut être utilisé un peu comme une graine afin de créer des séquences reproductibles de nombres aléatoires. Par exemple:

import numpy as np

# randomly initialize the RNG from some platform-dependent source of entropy
np.random.seed(None)

# get the initial state of the RNG
st0 = np.random.get_state()

# draw some random numbers
print(np.random.randint(0, 100, 10))
# [ 8 76 76 33 77 26  3  1 68 21]

# set the state back to what it was originally
np.random.set_state(st0)

# draw again
print(np.random.randint(0, 100, 10))
# [ 8 76 76 33 77 26  3  1 68 21]
51
ali_m

J'ai fortement modifié cette réponse après avoir découvert quelques détails supplémentaires sur le problème rencontré. Dans l’état actuel des choses, j’espère que cela servira de clarification de la réponse de ALi_m et de correction importante de la réponse de Dong Justin.

Ce sont mes conclusions:

  1. Après avoir défini la graine aléatoire à l’aide de np.random.seed(X), vous pouvez le retrouver à l’aide de np.random.get_state()[1][0].
  2. Cela ne vous sera toutefois que peu utile.

La sortie des sections de code suivantes vous montrera pourquoi les deux instructions sont correctes.


Statement 1 - vous pouvez trouver la graine aléatoire en utilisant np.random.get_state()[1][0].

Si vous définissez la graine aléatoire à l'aide de np.random.seed(123), vous pouvez récupérer l'état aléatoire sous forme de tuple à l'aide de state = np.random.get_state(). Ci-dessous, un aperçu plus détaillé de state (J'utilise l'explorateur de variables dans Spyder). J'utilise une capture d'écran car utiliser print(state) va inonder votre console à cause de la taille du tableau dans le deuxième élément du Tuple.

 enter image description here

Vous pouvez facilement voir 123 en tant que premier nombre du tableau contenu dans le deuxième élément. Et en utilisant seed = np.random.get_state()[1][0]will vous donnerez 123. Parfait? Pas tout à fait, car:

Affirmation 2 - Cela ne vous servira cependant à rien:

Cela peut sembler vrai au début cependant, car vous pouvez utilisez np.random.seed(123), récupérez le même numéro avec seed = np.random.get_state()[1][0], réinitialisez la valeur de départ avec np.random.seed(444), puis (apparemment) le rétablissez sur le scénario 123 avec np.random.seed(seed). Mais vous saurez déjà ce que votre graine aléatoire était auparavant, vous n’auriez donc pas besoin de le faire de cette façon. La prochaine section de code montrera également que vous ne pouvez pas prendre le premier nombre d'aucun état aléatoire en utilisant np.random.get_state()[1][0] et vous attendre à recréer ce scénario exact. Notez que vous devrez probablement arrêter et redémarrer votre noyau complètement (ou appeler np.random.seed(None)) pour pouvoir le voir.

L'extrait suivant utilise np.random.randint() pour générer 5 nombres entiers aléatoires compris entre -10 et 10, ainsi que pour stocker des informations sur le processus:

_ {Snippet 1} _

# 1. Imports
import pandas as pd
import numpy as np

# 2. set random seed
#seedSet = None
seedSet = 123
np.random.seed(seedSet)

# 3. describe random state
state = np.random.get_state()
state5 = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]

# 4. generate random numbers
random = np.random.randint(-10, 10, size = 5)

# 5. organize and present findings
df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)

Notez que la colonne nommée seedState est identique au premier nombre sous state. J'aurais pu l'imprimer en tant que numéro isolé, mais je voulais tout garder au même endroit. Notez également que seedSet = 123 et np.random.seed(seedSet) ont jusqu’à présent été commentés. Et comme aucune graine aléatoire n’a été définie, vos chiffres seront différents des miens. Mais ce n’est pas ce qui est important ici, mais bien la cohérence interne de vos résultats:

Sortie 1:

   random seedSet   seedState       state
0       2    None  1558056443  1558056443
1      -1    None  1558056443  1808451632
2       4    None  1558056443   730968006
3      -4    None  1558056443  3568749506
4      -6    None  1558056443  3809593045

Dans ce cas particulier, seed = np.random.get_state()[1][0] est égal à 1558056443. Et en suivant la logique de la réponse de Dong Justins (ainsi que ma propre réponse avant cette modification), vous pouvez définir la graine aléatoire avec np.random.seed(1558056443) et obtenir le même état aléatoire. Le prochain extrait montrera que vous ne pouvez pas:

_ {Extrait 2} _

# 1. Imports
import pandas as pd
import numpy as np

# 2. set random seed
#seedSet = None
seedSet = 1558056443
np.random.seed(seedSet)

# 3. describe random state
#state = np.random.get_state()
state = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]

# 4. generate random numbers
random = np.random.randint(-10, 10, size = 5)

# 5. organize and present findings
df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)

Sortie 2:

   random     seedSet   seedState       state
0       8  1558056443  1558056443  1558056443
1       3  1558056443  1558056443  1391218083
2       7  1558056443  1558056443  2754892524
3      -8  1558056443  1558056443  1971852777
4       4  1558056443  1558056443  2881604748

Regarde la différence? np.random.get_state()[1][0] est identique pour les sorties 1 et 2, mais le reste de la sortie ne l’est pas (le plus important est que les nombres aléatoires ne sont pas identiques). Ainsi, comme ALi_m l’a déjà clairement indiqué:

Il est donc impossible de mapper chaque état RNG sur une graine entière unique.

8
vestland

Vérifiez le premier élément du tableau renvoyé par np.random.get_state(), il me semble que le germe est aléatoire.

0
Dong Justin