Créez systématiquement le même tableau numpy aléatoire

89

J'attends qu'un autre développeur termine un morceau de code qui renverra un tableau np de forme (100,2000) avec des valeurs de -1,0 ou 1.

En attendant, je souhaite créer au hasard un tableau des mêmes caractéristiques afin de pouvoir avoir une longueur d'avance sur mon développement et mes tests. Le fait est que je veux que ce tableau créé au hasard soit le même à chaque fois, de sorte que je ne teste pas contre un tableau qui ne cesse de changer sa valeur à chaque fois que je réexécute mon processus.

Je peux créer mon tableau comme ça, mais y a-t-il un moyen de le créer pour qu'il soit le même à chaque fois. Je peux décaper l'objet et le décoller, mais je me demande s'il existe un autre moyen.

r = np.random.randint(3, size=(100, 2000)) - 1
Idr
la source

Réponses:

84

Il suffit de semer le générateur de nombres aléatoires avec une valeur fixe, par exemple

numpy.random.seed(42)

De cette façon, vous obtiendrez toujours la même séquence de nombres aléatoires.

Sven Marnach
la source
43
Quelqu'un s'est faufilé dans la numpy.random.seed()fonction alors que je ne faisais pas attention. :-) Je l'ai laissé intentionnellement hors du module d'origine. Je recommande aux gens d'utiliser leurs propres instances RandomStateet de faire circuler ces objets.
Robert Kern
6
Robert est un contributeur majeur à numpy. Je pense que nous devrions donner un peu de poids à son opinion.
obsolète
10
@deprecated: je suis reconnaissant pour le travail de Robert, mais son travail ne remplace pas la justification de la recommandation. De plus, si l'utilisation de numpy.random.seed()est déconseillée, cela doit être mentionné dans la documentation . Apparemment, les autres contributeurs à NumPy ne partagent pas l'opinion de Robert. Aucune offense du tout, je suis juste curieuse.
Sven Marnach
13
C'est la même chose que l'utilisation random.seedou l'utilisation d'un random.Randomobjet dans la bibliothèque standard Python. Si vous utilisez random.seedou numpy.random.seed, vous amorcez toutes les instances aléatoires, à la fois dans votre code et dans tout code que vous appelez ou dans tout code exécuté dans la même session que la vôtre. Si ces choses dépendent du fait que ces choses sont en fait aléatoires, alors vous commencez à rencontrer des problèmes. Si vous déployez du code qui définit la valeur de départ aléatoire, vous pouvez introduire une vulnérabilité de sécurité.
asmeurer
3
@asmeurer Quiconque utilise un générateur de nombres pseudo-aléatoires à des fins de sécurité ne sait probablement pas ce qu'il fait.
JAB
191

Créez votre propre instance de numpy.random.RandomState()avec la graine choisie. Ne l'utilisez numpy.random.seed()que pour contourner des bibliothèques inflexibles qui ne vous permettent pas de transmettre votre propre RandomStateinstance.

[~]
|1> from numpy.random import RandomState

[~]
|2> prng = RandomState(1234567890)

[~]
|3> prng.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])

[~]
|4> prng2 = RandomState(1234567890)

[~]
|5> prng2.randint(-1, 2, size=10)
array([ 1,  1, -1,  0,  0, -1,  1,  0, -1, -1])
Robert Kern
la source
7
Avez-vous une justification pour votre recommandation? Quel est le problème avec numpy.random.seed()? Je sais que ce n'est pas thread-safe, mais c'est vraiment pratique si vous n'avez pas besoin de thread-safety.
Sven Marnach
52
C'est surtout pour former de bonnes habitudes. Vous n'avez peut-être pas besoin de flux indépendants maintenant, mais Sven-6-mois-à partir de maintenant pourrait. Si vous écrivez vos bibliothèques pour utiliser les méthodes directement à partir de numpy.random, vous ne pourrez pas créer de flux indépendants ultérieurement. Il est également plus facile d'écrire des bibliothèques avec l'intention de contrôler les flux PRNG. Il existe toujours plusieurs façons d'entrer dans votre bibliothèque, et chacune d'elles devrait avoir un moyen de contrôler la graine. Faire circuler des objets PRNG est une façon plus propre de le faire que de se fier numpy.random.seed(). Malheureusement, cette zone de commentaire est trop courte pour contenir plus d'exemples. :-)
Robert Kern
25
Une autre façon de décrire le raisonnement de Robert: l'utilisation de numpy.random.seed utilise une variable globale pour conserver l'état PRNG, et les mêmes raisons standard pour lesquelles les variables globales sont mauvaises s'appliquent ici.
Robie Basak
9
Si vous voulez que les PRNG soient indépendants, ne les semez pas avec quoi que ce soit. Utilisez simplement numpy.random.RandomState()sans arguments. Cela amorcera l'état avec des valeurs uniques tirées des installations de votre système d'exploitation pour de telles choses ( /dev/urandomsur les machines UNIX et l'équivalent Windows là-bas). Si cela numpy.random.RandomState(1234567890)ne fonctionne pas pour vous, veuillez montrer exactement ce que vous avez tapé et exactement le message d'erreur que vous avez reçu.
Robert Kern
5
Pas une bonne idée. Utilisez numpy.random.RandomState()sans arguments pour les meilleurs résultats.
Robert Kern
3

Si vous utilisez d'autres fonctions reposant sur un état aléatoire, vous ne pouvez pas simplement définir une valeur de départ globale, mais plutôt créer une fonction pour générer votre liste aléatoire de nombres et définir la valeur de départ comme paramètre de la fonction. Cela ne dérangera aucun autre générateur aléatoire dans le code:

# Random states
def get_states(random_state, low, high, size):
    rs = np.random.RandomState(random_state)
    states = rs.randint(low=low, high=high, size=size)
    return states

# Call function
states = get_states(random_state=42, low=2, high=28347, size=25)
mari756h
la source
3

Il est important de comprendre quelle est la graine d'un générateur aléatoire et quand / comment elle est définie dans votre code (vérifiez par exemple ici pour une belle explication de la signification mathématique de la graine).

Pour cela, vous devez définir la graine en faisant:

random_state = np.random.RandomState(seed=your_favorite_seed_value)

Il est alors important de générer les nombres aléatoires à partir de random_state et non de np.random. Ie vous devriez faire:

random_state.randint(...)

au lieu de

np.random.randint(...) 

qui créera une nouvelle instance de RandomState () et utilisera essentiellement l'horloge interne de votre ordinateur pour définir la graine.

t_sic
la source
2

Je veux juste clarifier quelque chose en ce qui concerne la réponse @Robert Kern au cas où cela ne serait pas clair. Même si vous utilisez le, RandomStatevous devrez l'initialiser chaque fois que vous appelez une méthode aléatoire numpy comme dans l'exemple de Robert, sinon vous obtiendrez les résultats suivants.

Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:07:31) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> prng = np.random.RandomState(2019)
>>> prng.randint(-1, 2, size=10)
array([-1,  1,  0, -1,  1,  1, -1,  0, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([-1, -1, -1,  0, -1, -1,  1,  0, -1, -1])
>>> prng.randint(-1, 2, size=10)
array([ 0, -1, -1,  0,  1,  1, -1,  1, -1,  1])
>>> prng.randint(-1, 2, size=10)
array([ 1,  1,  0,  0,  0, -1,  1,  1,  0, -1])
Kirk Walla
la source