Que fait numpy.random.seed (0)?

282

Que fait np.random.seedle code ci-dessous d'un didacticiel Scikit-Learn? Je ne suis pas très familier avec les générateurs d'états aléatoires de NumPy, donc j'apprécierais vraiment les termes d'un profane expliquant cela.

np.random.seed(0)
indices = np.random.permutation(len(iris_X))
covariance
la source

Réponses:

559

np.random.seed(0) rend les nombres aléatoires prévisibles

>>> numpy.random.seed(0) ; numpy.random.rand(4)
array([ 0.55,  0.72,  0.6 ,  0.54])
>>> numpy.random.seed(0) ; numpy.random.rand(4)
array([ 0.55,  0.72,  0.6 ,  0.54])

Avec la réinitialisation de la graine (à chaque fois), le même ensemble de chiffres apparaîtra à chaque fois.

Si la graine aléatoire n'est pas réinitialisée, des nombres différents apparaissent à chaque invocation:

>>> numpy.random.rand(4)
array([ 0.42,  0.65,  0.44,  0.89])
>>> numpy.random.rand(4)
array([ 0.96,  0.38,  0.79,  0.53])

Les nombres (pseudo-) aléatoires fonctionnent en commençant par un nombre (la graine), en le multipliant par un grand nombre, en ajoutant un décalage, puis en prenant le modulo de cette somme. Le nombre résultant est ensuite utilisé comme graine pour générer le nombre "aléatoire" suivant. Lorsque vous définissez la graine (à chaque fois), cela fait la même chose à chaque fois, en vous donnant les mêmes chiffres.

Si vous voulez des nombres apparemment aléatoires, ne définissez pas la graine. Si vous avez du code qui utilise des nombres aléatoires que vous souhaitez déboguer, cependant, il peut être très utile de définir la valeur de départ avant chaque exécution afin que le code fasse la même chose chaque fois que vous l'exécutez.

Pour obtenir le nombre le plus aléatoire de chaque série, appelez numpy.random.seed(). Cela amènera numpy à définir la valeur de départ sur un nombre aléatoire obtenu à partir de /dev/urandomou son analogue Windows ou, si aucun de ceux-ci n'est disponible, il utilisera l'horloge.

Pour plus d'informations sur l'utilisation de graines pour générer des nombres pseudo-aléatoires, voir wikipedia .

John1024
la source
86
Cette réponse doit être ajoutée à la documentation de numpy. Je vous remercie.
Gorjanz
8
De plus, lorsque vous appelez numpy.random.seed(None), il "essaiera de lire les données de / dev / urandom (ou l'analogue de Windows) si elles sont disponibles ou les graines de l'horloge dans le cas contraire".
Jonathan
1
@Jonathan Excellent point sur numpy.random.seed(None). J'ai mis à jour la réponse avec ces informations et un lien vers les documents.
John1024
@ curio1729 L'implémentation peut varier d'un système d'exploitation à l'autre mais numpy essaie de rendre ses commandes, y compris seed, compatibles.
John1024
1
@ L3viathan Bon point! Pour être plus complet et précis, j'aurais dû mentionner qu'un décalage est ajouté. Réponse mise à jour. Pour ceux qui veulent plus de détails, j'ai également ajouté un lien vers la discussion de wikipedia sur les générateurs de nombres pseudo-aléatoires.
John1024
38

Si vous définissez np.random.seed(a_fixed_number)chaque fois que vous appelez l'autre fonction aléatoire du numpy, le résultat sera le même:

>>> import numpy as np
>>> np.random.seed(0) 
>>> perm = np.random.permutation(10) 
>>> print perm 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10) 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.rand(4) 
[0.5488135  0.71518937 0.60276338 0.54488318]
>>> np.random.seed(0) 
>>> print np.random.rand(4) 
[0.5488135  0.71518937 0.60276338 0.54488318]

Cependant, si vous l'appelez une seule fois et utilisez diverses fonctions aléatoires, les résultats seront toujours différents:

>>> import numpy as np
>>> np.random.seed(0) 
>>> perm = np.random.permutation(10)
>>> print perm 
[2 8 4 9 1 6 7 3 0 5]
>>> np.random.seed(0) 
>>> print np.random.permutation(10)
[2 8 4 9 1 6 7 3 0 5]
>>> print np.random.permutation(10) 
[3 5 1 2 9 8 0 6 7 4]
>>> print np.random.permutation(10) 
[2 3 8 4 5 1 0 6 9 7]
>>> print np.random.rand(4) 
[0.64817187 0.36824154 0.95715516 0.14035078]
>>> print np.random.rand(4) 
[0.87008726 0.47360805 0.80091075 0.52047748]
Zhun Chen
la source
3
Existe-t-il une fonction qui peut être appelée une fois de telle sorte que la valeur de départ aléatoire est définie pour tous les np.randomappels suivants jusqu'à ce que la valeur de départ soit modifiée? Devoir l'appeler à chaque fois semble inutilement verbeux et facile à oublier.
Lubed Up Slug
@LubedUpSlug vous pouvez les décorer - au moins pour certains cas simples, j'ai testé que cela devrait fonctionner. def seed_first(fun, seed=0):| \tdef wrapped(*args, **kwargs):| \t\tnp.random.seed(seed)| \t\treturn fun(*args, **kwargs)| \treturn wrapped, puis for m in np.random.__all__:| \tif m != 'seed':| \t\tsetattr(np.random, m, seed_first(getattr(np.random, m)))Cependant, cela pourrait conduire à des bugs très subtils et à un comportement étrange à long terme. (Remplacez \ t par quatre espaces et | par des sauts de ligne ...)
Sebastian Höffner
1
@ SebastianHöffner merci pour votre commentaire. Ma question était un peu erronée car j'étais confus par la phrase "Cependant, si vous l'appelez une seule fois et utilisez diverses fonctions aléatoires, les résultats seront toujours différents:" Appeler np.random.seed()une fois au début d'un programme produira toujours le même résultat pour la même valeur de départ, car les appels de np.randomfonctions suivants modifieront de manière déterministe la valeur de départ pour les appels suivants. Appeler np.random.seed()avant chaque appel aux np.randomfonctions produira probablement des résultats indésirables.
Lubed Up Slug
17

Comme indiqué, numpy.random.seed (0) définit la valeur de départ aléatoire à 0, donc les nombres pseudo-aléatoires que vous obtenez de random commenceront au même point. Cela peut être bon pour le débogage dans certains cas. CEPENDANT, après quelques lectures, cela semble être la mauvaise façon de procéder, si vous avez des threads car ce n'est pas sûr pour les threads.

à partir de différences entre numpy-random-et-random-random-in-python :

Pour numpy.random.seed (), la principale difficulté est qu'il n'est pas adapté aux threads - c'est-à-dire qu'il n'est pas sûr de l'utiliser si vous avez plusieurs threads d'exécution différents, car il n'est pas garanti de fonctionner si deux threads différents s'exécutent la fonction en même temps. Si vous n'utilisez pas de threads, et si vous pouvez raisonnablement vous attendre à ce que vous n'ayez pas besoin de réécrire votre programme de cette façon à l'avenir, numpy.random.seed () devrait convenir à des fins de test. S'il y a une raison de soupçonner que vous pourriez avoir besoin de threads à l'avenir, il est beaucoup plus sûr à long terme de faire comme suggéré et de créer une instance locale de la classe numpy.random.Random. Pour autant que je sache, random.random.seed () est thread-safe (ou du moins, je n'ai trouvé aucune preuve du contraire).

exemple de la façon de procéder:

from numpy.random import RandomState
prng = RandomState()
print prng.permutation(10)
prng = RandomState()
print prng.permutation(10)
prng = RandomState(42)
print prng.permutation(10)
prng = RandomState(42)
print prng.permutation(10)

peut donner:

[3 0 4 6 8 2 1 9 7 5]

[1 6 9 0 2 7 8 3 5 4]

[8 1 5 0 7 2 9 4 3 6]

[8 1 5 0 7 2 9 4 3 6]

Enfin, notez qu'il peut y avoir des cas où l'initialisation à 0 (par opposition à une graine qui n'a pas tous les bits 0) peut entraîner des distributions non uniformes pour quelques premières itérations en raison du fonctionnement de xor, mais cela dépend de l'algorithme , et dépasse mes préoccupations actuelles et la portée de cette question.

ntg
la source
12

Je l'ai utilisé très souvent dans les réseaux de neurones. Il est bien connu que lorsque nous commençons à former un réseau de neurones, nous initialisons au hasard les poids. Le modèle est formé sur ces poids sur un ensemble de données particulier. Après nombre d'époques, vous obtenez un ensemble de poids formé.

Supposons maintenant que vous souhaitiez vous entraîner à nouveau à partir de zéro ou que vous souhaitiez transmettre le modèle à d'autres pour reproduire vos résultats, les poids seront à nouveau initialisés en nombres aléatoires qui seront généralement différents des précédents. Les poids entraînés obtenus après le même nombre d'époques (en conservant les mêmes données et d'autres paramètres) que le précédent varieront. Le problème est que votre modèle n'est plus reproductible, c'est que chaque fois que vous entraînez votre modèle à partir de zéro, il vous propose différents ensembles de poids. En effet, le modèle est initialisé à chaque fois par des nombres aléatoires différents.

Que se passe-t-il si chaque fois que vous commencez à vous entraîner à partir de zéro, le modèle est initialisé avec le même ensemble de poids d'initialisation aléatoires? Dans ce cas, votre modèle pourrait devenir reproductible. Ceci est réalisé par numpy.random.seed (0). En mentionnant seed () à un nombre particulier, vous vous accrochez toujours au même ensemble de nombres aléatoires.

A Santosh
la source
3

Imaginez que vous montrez à quelqu'un comment coder quelque chose avec un tas de nombres "aléatoires". En utilisant numpy seed, ils peuvent utiliser le même numéro de graine et obtenir le même ensemble de nombres "aléatoires".

Ce n'est donc pas exactement aléatoire, car un algorithme crache les nombres, mais il ressemble à un groupe généré de manière aléatoire.

cjHerold
la source
0

Une valeur de départ aléatoire spécifie le point de départ lorsqu'un ordinateur génère une séquence de nombres aléatoires.

Par exemple, supposons que vous vouliez générer un nombre aléatoire dans Excel (Remarque: Excel définit une limite de 9999 pour la valeur de départ). Si vous entrez un nombre dans la zone Aléatoire au cours du processus, vous pourrez à nouveau utiliser le même ensemble de nombres aléatoires. Si vous avez tapé «77» dans la zone et que vous avez tapé «77» la prochaine fois que vous exécutez le générateur de nombres aléatoires, Excel affichera ce même ensemble de nombres aléatoires. Si vous tapez «99», vous obtiendrez un ensemble de nombres entièrement différent. Mais si vous revenez à une graine de 77, vous obtiendrez le même ensemble de nombres aléatoires avec lequel vous avez commencé.

Par exemple, «prenez un nombre x, ajoutez 900 + x, puis soustrayez 52». Pour que le processus démarre, vous devez spécifier un numéro de départ, x (la graine). Prenons le numéro de départ 77:

Ajouter 900 + 77 = 977 Soustraire 52 = 925 En suivant le même algorithme, le deuxième nombre «aléatoire» serait:

900 + 925 = 1825 Soustraire 52 = 1773 Cet exemple simple suit un modèle, mais les algorithmes derrière la génération de numéros d'ordinateur sont beaucoup plus compliqués

sunidhi mittal
la source
0

Tous les nombres aléatoires générés après avoir défini une valeur de départ particulière sont les mêmes sur toutes les plateformes / systèmes.

Prashant
la source
0
numpy.random.seed(0)
numpy.random.randint(10, size=5)

Cela produit la sortie suivante: array([5, 0, 3, 3, 7]) Encore une fois, si nous exécutons le même code, nous obtiendrons le même résultat.

Maintenant, si nous changeons la valeur de départ 0 en 1 ou autres:

numpy.random.seed(1)
numpy.random.randint(10, size=5)

Cela produit la sortie suivante: array([5 8 9 5 0])mais maintenant la sortie n'est pas la même que ci-dessus.

Humayun Ahmad Rajib
la source
0

Toutes les réponses ci-dessus montrent l'implémentation de np.random.seed()dans le code. Je ferai de mon mieux pour expliquer brièvement pourquoi cela se produit réellement. Les ordinateurs sont des machines conçues sur la base d'algorithmes prédéfinis. Toute sortie d'un ordinateur est le résultat de l'algorithme implémenté sur l'entrée. Donc, lorsque nous demandons à un ordinateur de générer des nombres aléatoires, bien sûr, ils sont aléatoires, mais l'ordinateur ne les a pas simplement créés au hasard!

Ainsi, lorsque nous écrivons, np.random.seed(any_number_here)l'algorithme génère un ensemble particulier de nombres qui est unique à l'argument any_number_here. C'est presque comme si un ensemble particulier de nombres aléatoires pouvait être obtenu si nous transmettons l'argument correct. Mais cela nous obligera à savoir comment fonctionne l'algorithme, ce qui est assez fastidieux.

Ainsi, par exemple, si j'écris np.random.seed(10) l'ensemble de nombres particulier que j'obtiens, il restera le même même si j'exécute la même ligne après 10 ans, à moins que l'algorithme ne change.

WadeWilson
la source