110 votes

Différences entre numpy.random et random.random en Python

J'ai un gros script en Python. Je me suis inspiré du code d'autres personnes et j'ai fini par utiliser l'outil numpy.random pour certaines choses (par exemple pour créer un tableau de nombres aléatoires tirés d'une distribution binomiale) et à d'autres endroits, j'utilise le module random.random .

Quelqu'un peut-il me dire quelles sont les principales différences entre les deux ? En regardant la page web de la doc pour chacun des deux, il me semble que numpy.random a juste plus de méthodes, mais je ne vois pas bien en quoi la génération des nombres aléatoires est différente.

La raison de ma question est que j'ai besoin d'ensemencer mon programme principal à des fins de débogage. Mais cela ne fonctionne que si j'utilise le même générateur de nombres aléatoires dans tous les modules que j'importe, est-ce correct ?

De plus, j'ai lu ici, dans un autre post, une discussion sur le fait de NE PAS utiliser numpy.random.seed() mais je n'ai pas vraiment compris pourquoi c'était une si mauvaise idée. J'apprécierais vraiment que quelqu'un m'explique pourquoi c'est le cas.

135voto

Hannele Points 2906

Vous avez déjà fait de nombreuses observations correctes !

À moins que vous ne souhaitiez ensemencer les deux générateurs aléatoires, il est probablement plus simple à long terme de choisir un générateur ou l'autre. Mais si vous avez besoin d'utiliser les deux, alors oui, vous devrez également les ensemencer tous les deux, car ils génèrent des nombres aléatoires indépendamment l'un de l'autre.

Para numpy.random.seed() La principale difficulté réside dans le fait qu'il n'est pas "thread-safe", c'est-à-dire qu'il n'est pas sûr d'être utilisé si vous disposez d'un système de gestion de la qualité. plusieurs fils d'exécution différents car son fonctionnement n'est pas garanti si deux threads différents exécutent la fonction en même temps. Si vous n'utilisez pas de threads, et si vous pouvez raisonnablement penser que vous n'aurez pas besoin de réécrire votre programme de cette façon à l'avenir, numpy.random.seed() devrait aller bien. Si vous avez la moindre raison de penser que vous pourriez avoir besoin de fils à l'avenir, il est beaucoup plus sûr à long terme de faire ce qui est suggéré, et de créer une instance locale de la numpy.random.Random classe . Pour autant que je puisse dire, random.random.seed() est thread-safe (ou du moins, je n'ai pas trouvé de preuve du contraire).

El numpy.random contient quelques distributions de probabilité supplémentaires couramment utilisées dans la recherche scientifique, ainsi que quelques fonctions pratiques pour générer des tableaux de données aléatoires. Le site random.random est un peu plus légère, et devrait convenir si vous ne faites pas de recherche scientifique ou d'autres types de travaux en statistiques.

Sinon, ils utilisent tous deux le Séquence de torsion de Mersenne pour générer leurs nombres aléatoires, et ils sont tous deux complètement déterministes - c'est-à-dire que si vous connaissez quelques informations clés, il est possible de prédire avec une absolue certitude quel numéro viendra ensuite . Pour cette raison, ni numpy.random, ni random.random ne conviennent pour une utilisations cryptographiques sérieuses . Mais comme la séquence est très très longue, les deux sont parfaits pour générer des nombres aléatoires dans les cas où vous ne craignez pas que des personnes essaient de faire de l'ingénierie inverse sur vos données. C'est également la raison pour laquelle il est nécessaire d'ensemencer la valeur aléatoire : si vous commencez au même endroit à chaque fois, vous obtiendrez toujours la même séquence de nombres aléatoires !

En passant, si vous faire si vous avez besoin d'un caractère aléatoire de niveau cryptographique, vous devez utiliser la fonction secrets ou quelque chose comme Crypto.aléatoire si vous utilisez une version de Python antérieure à Python 3.6.

14 votes

Dans un autre ordre d'idées, il est parfois nécessaire de recourir à ni En effet, le tordeur de Mersenne ne produit pas de séquences aléatoires d'une entropie suffisante pour les besoins de la cryptographie (et de certaines activités scientifiques inhabituelles). Dans ces rares cas, vous avez souvent besoin de Crypto.aléatoire qui est capable d'utiliser des sources d'entropie spécifiques à l'OS pour générer des séquences aléatoires non déterministes d'une qualité bien supérieure à celle que l'on peut obtenir à partir de l'OS. random.random seul. Vous n'en avez généralement pas besoin.

0 votes

Merci Hannnele. Vos idées sont vraiment très utiles ! Il s'avère que je ne peux pas m'en sortir en utilisant UN SEUL générateur de nombres aléatoires (qui doit être numpy puisque random ne produit pas de distributions binomiales) car certaines parties de mon programme appellent un autre programme qui utilise random. Je vais devoir ensemencer les deux générateurs.

2 votes

"Si vous savez quel nombre vous avez maintenant, il est possible de prédire avec une certitude absolue quel sera le prochain nombre." Je pense que cette affirmation doit être clarifiée. Ce que l'on veut dire, c'est que si vous connaissez le état interne du générateur, vous pouvez reproduire la séquence - c'est ce que vous faites lorsque vous ensemencez le générateur. Étant donné un seul nombre produit par le générateur, vous ne pouvez pas prédire le nombre suivant. La période est tellement grande qu'il faudrait probablement une longue séquence de nombres avant de pouvoir calculer où l'on se trouve sur la séquence pseudo-aléatoire et donc prédire le prochain.

12voto

lmiguelvargasf Points 9693

De Python pour l'analyse des données le module numpy.random complète le programme Python random avec des fonctions permettant de générer efficacement des tableaux entiers de valeurs d'échantillons à partir de nombreux types de distributions de probabilité.

En revanche, la fonction intégrée de Python random n'échantillonne qu'une seule valeur à la fois, alors que le module numpy.random peut générer un très grand échantillon plus rapidement. Utilisation de la fonction magique d'IPython %timeit on peut voir quel module est le plus performant :

In [1]: from random import normalvariate
In [2]: N = 1000000

In [3]: %timeit samples = [normalvariate(0, 1) for _ in xrange(N)]
1 loop, best of 3: 963 ms per loop

In [4]: %timeit np.random.normal(size=N)
10 loops, best of 3: 38.5 ms per loop

3voto

La source de l'ensemencement et le profil de distribution utilisé vont affecter les résultats - si vous recherchez un caractère aléatoire cryptographique, l'ensemencement à partir de os.urandom() obtiendra des octets aléatoires presque réels à partir de la conversation du périphérique (c'est-à-dire Ethernet ou disque) (c'est-à-dire /dev/random sur BSD).

Cela vous évitera de donner une graine et de générer ainsi des nombres aléatoires déterministes. Cependant, les appels aléatoires vous permettent d'ajuster les nombres à une distribution (ce que j'appelle le caractère aléatoire scientifique - en fin de compte, tout ce que vous voulez, c'est une distribution de nombres aléatoires en forme de courbe en cloche, numpy est le meilleur moyen d'y parvenir.

Donc, oui, tenez-vous en à un seul générateur, mais décidez du caractère aléatoire que vous voulez - aléatoire, mais seulement à partir d'une courbe de distribution, ou aussi aléatoire que vous pouvez l'obtenir sans un dispositif quantique.

0 votes

Merci beaucoup Paul, votre réponse m'a été très utile ! Je ne cherche pas de caractère aléatoire cryptographique, je fais de la modélisation mathématique et les nombres pseudo-aléatoires me suffisent. Il s'avère que je ne peux pas m'en tenir à un seul générateur comme je le voulais puisque j'ai besoin de numpy pour la distribution binomiale et que mon programme appelle un autre programme qui utilise le hasard :(

0voto

Jimmy Wu Points 44

J'ai été surpris par la randint(a, b) existe à la fois dans numpy.random y random mais ils ont des comportements différents pour la borne supérieure.

random.randint(a, b) renvoie un entier aléatoire N tel que a <= N <= b . Alias pour randrange(a, b+1) . Il a b inclusive. documentation aléatoire

Cependant, si vous appelez numpy.random.randint(a, b) il retournera du bas (inclus) au haut (exclusif). Documentation sur Numpy

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X